hashed to prevent leaking information about the kernel memory layout. This
has the added benefit of providing a unique identifier. On 64-bit machines
the first 32 bits are zeroed. The kernel will print ``(ptrval)`` until it
-gathers enough entropy. If you *really* want the address see %px below.
+gathers enough entropy.
+
+When possible, use specialised modifiers such as %pS or %pB (described below)
+to avoid the need of providing an unhashed address that has to be interpreted
+post-hoc. If not possible, and the aim of printing the address is to provide
+more information for debugging, use %p and boot the kernel with the
+``no_hash_pointers`` parameter during debugging, which will print all %p
+addresses unmodified. If you *really* always want the unmodified address, see
+%px below.
+
+If (and only if) you are printing addresses as a content of a virtual file in
+e.g. procfs or sysfs (using e.g. seq_printf(), not printk()) read by a
+userspace process, use the %pK modifier described below instead of %p or %px.
Error Pointers
--------------
users. The behaviour of %pK depends on the kptr_restrict sysctl - see
Documentation/admin-guide/sysctl/kernel.rst for more details.
+This modifier is *only* intended when producing content of a file read by
+userspace from e.g. procfs or sysfs, not for dmesg. Please refer to the
+section about %p above for discussion about how to manage hashing pointers
+in printk().
+
Unmodified Addresses
--------------------
grep'able. If in the future we need to modify the way the kernel handles
printing pointers we will be better equipped to find the call sites.
+Before using %px, consider if using %p is sufficient together with enabling the
+``no_hash_pointers`` kernel parameter during debugging sessions (see the %p
+description above). One valid scenario for %px might be printing information
+immediately before a panic, which prevents any sensitive information to be
+exploited anyway, and with %px there would be no need to reproduce the panic
+with no_hash_pointers.
+
Pointer Differences
-------------------
::
- %pGp referenced|uptodate|lru|active|private
+ %pGp referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff
%pGg GFP_USER|GFP_DMA32|GFP_NOWARN
%pGv read|exec|mayread|maywrite|mayexec|denywrite
Passed by reference.
+ V4L2 and DRM FourCC code (pixel format)
+ ---------------------------------------
+
+ ::
+
+ %p4cc
+
+ Print a FourCC code used by V4L2 or DRM, including format endianness and
+ its numerical value as hexadecimal.
+
+ Passed by reference.
+
+ Examples::
+
+ %p4cc BG12 little-endian (0x32314742)
+ %p4cc Y10 little-endian (0x20303159)
+ %p4cc NV12 big-endian (0xb231564e)
+
Thanks
======
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
-F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
F: drivers/counter/104-quad-8.c
ACCES PCI-IDIO-16 GPIO DRIVER
F: Documentation/scsi/advansys.rst
F: drivers/scsi/advansys.c
+ADVANTECH SWBTN DRIVER
+S: Maintained
+F: drivers/platform/x86/adv_swbutton.c
+
ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
S: Supported
F: Documentation/i2c/busses/i2c-ali1563.rst
F: drivers/i2c/busses/i2c-ali1563.c
+ALIENWARE WMI DRIVER
+S: Maintained
+F: drivers/platform/x86/dell/alienware-wmi.c
+
ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
T: git git://people.freedesktop.org/~agd5f/linux
F: drivers/gpu/drm/amd/display/
-AMD ENERGY DRIVER
-S: Maintained
-F: Documentation/hwmon/amd_energy.rst
-F: drivers/hwmon/amd_energy.c
-
AMD FAM15H PROCESSOR POWER MONITORING DRIVER
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: Documentation/devicetree/bindings/iio/*/adi,*
-F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
+F: Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc249*
F: drivers/iio/amplifiers/hmc425a.c
S: Supported
F: Documentation/devicetree/bindings/display/snps,arcpgu.txt
- F: drivers/gpu/drm/arc/
+ F: drivers/gpu/drm/tiny/arcpgu.c
ARCNET NETWORK LAYER
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
F: arch/arm/mach-sunxi/
F: arch/arm64/boot/dts/allwinner/
F: drivers/clk/sunxi-ng/
F: drivers/pinctrl/sunxi/
F: drivers/soc/sunxi/
+N: allwinner
N: sun[x456789]i
N: sun50i
F: arch/arm64/boot/dts/amazon/
F: drivers/*/*alpine*
+ARM/APPLE MACHINE SUPPORT
+S: Maintained
+W: https://asahilinux.org
+B: https://github.com/AsahiLinux/linux/issues
+C: irc://chat.freenode.net/asahi-dev
+T: git https://github.com/AsahiLinux/linux.git
+F: Documentation/devicetree/bindings/arm/apple.yaml
+F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
+F: arch/arm64/boot/dts/apple/
+F: drivers/irqchip/irq-apple-aic.c
+F: include/dt-bindings/interrupt-controller/apple-aic.h
+
ARM/ARTPEC MACHINE SUPPORT
F: Documentation/trace/coresight/*
F: drivers/hwtracing/coresight/*
F: include/dt-bindings/arm/coresight-cti-dt.h
+F: include/linux/coresight*
F: tools/perf/arch/arm/util/auxtrace.c
F: tools/perf/arch/arm/util/cs-etm.c
F: tools/perf/arch/arm/util/cs-etm.h
F: drivers/*/*/*npcm*
F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
+ARM/NUVOTON WPCM450 ARCHITECTURE
+S: Maintained
+F: Documentation/devicetree/bindings/*/*wpcm*
+F: arch/arm/boot/dts/nuvoton-wpcm450*
+F: arch/arm/mach-npcm/wpcm450.c
+F: drivers/*/*wpcm*
+
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
S: Orphan
F: drivers/usb/dwc3/dwc3-qcom.c
F: include/dt-bindings/*/qcom*
F: include/linux/*/qcom*
+F: include/linux/soc/qcom/
ARM/RADISYS ENP2611 MACHINE SUPPORT
N: rockchip
ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
S: Maintained
N: visconti
ARM/UNIPHIER ARCHITECTURE
-S: Orphan
+S: Maintained
F: Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
F: Documentation/devicetree/bindings/gpio/socionext,uniphier-gpio.yaml
F: Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml
S: Supported
W: https://github.com/linux-audit
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
+F: include/asm-generic/audit_*.h
F: include/linux/audit.h
F: include/uapi/linux/audit.h
F: kernel/audit*
+F: lib/*audit.c
AUXILIARY DISPLAY DRIVERS
F: include/linux/platform_data/b53.h
BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
+M: Nicolas Saenz Julienne <nsaenz@kernel.org>
F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
F: drivers/i2c/busses/i2c-brcmstb.c
+BROADCOM BRCMSTB UART DRIVER
+S: Maintained
+F: Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml
+F: drivers/tty/serial/8250/8250_bcm7271.c
+
BROADCOM BRCMSTB USB EHCI DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
+F: Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml
F: drivers/spi/spi-bcm-qspi.*
F: drivers/spi/spi-brcmstb-qspi.c
F: drivers/spi/spi-iproc-qspi.c
CHECKPATCH
S: Maintained
F: scripts/checkpatch.pl
+CHECKPATCH DOCUMENTATION
+S: Maintained
+F: Documentation/dev-tools/checkpatch.rst
+
CHINESE DOCUMENTATION
S: Maintained
F: Documentation/translations/zh_CN/
F: Documentation/process/code-of-conduct-interpretation.rst
F: Documentation/process/code-of-conduct.rst
+COMEDI DRIVERS
+S: Odd Fixes
+F: drivers/comedi/
+
COMMON CLK FRAMEWORK
W: http://www.armlinux.org.uk/
F: drivers/video/fbdev/cyber2000fb.*
-CYCLADES ASYNC MUX DRIVER
-S: Orphan
-W: http://www.cyclades.com/
-F: drivers/tty/cyclades.c
-F: include/linux/cyclades.h
-F: include/uapi/linux/cyclades.h
-
CYCLADES PC300 DRIVER
S: Orphan
-W: http://www.cyclades.com/
F: drivers/net/wan/pc300*
CYPRESS_FIRMWARE MEDIA DRIVER
DELL SMBIOS DRIVER
S: Maintained
F: drivers/platform/x86/dell/dell-smbios.*
DELL SMBIOS SMM DRIVER
S: Maintained
F: drivers/platform/x86/dell/dell-smbios-smm.c
DELL SMBIOS WMI DRIVER
S: Maintained
F: drivers/platform/x86/dell/dell-smbios-wmi.c
F: drivers/platform/x86/dell/dcdbas.*
DELL WMI DESCRIPTOR DRIVER
S: Maintained
F: drivers/platform/x86/dell/dell-wmi-descriptor.c
DELL WMI SYSMAN DRIVER
S: Maintained
F: Documentation/ABI/testing/sysfs-class-firmware-attributes
F: drivers/dma/dw-edma/
F: include/linux/dma/edma.h
+DESIGNWARE XDATA IP DRIVER
+S: Maintained
+F: Documentation/misc-devices/dw-xdata-pcie.rst
+F: drivers/misc/dw-xdata-pcie.c
+
DESIGNWARE USB2 DRD IP DRIVER
S: Maintained
W: http://lanana.org/docs/device-list/index.html
+DEVICE RESOURCE MANAGEMENT HELPERS
+S: Maintained
+F: include/linux/devm-helpers.h
+
DEVICE-MAPPER (LVM)
DMI/SMBIOS SUPPORT
S: Maintained
-T: quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git dmi-for-next
F: Documentation/ABI/testing/sysfs-firmware-dmi-tables
F: drivers/firmware/dmi-id.c
F: drivers/firmware/dmi_scan.c
X: Documentation/spi/
X: Documentation/userspace-api/media/
+DOCUMENTATION REPORTING ISSUES
+S: Maintained
+F: Documentation/admin-guide/reporting-issues.rst
+
DOCUMENTATION SCRIPTS
F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml
F: drivers/gpu/drm/panel/panel-boe-himax8279d.c
+ DRM DRIVER FOR CHIPONE ICN6211 MIPI-DSI to RGB CONVERTER BRIDGE
+ S: Maintained
+ F: Documentation/devicetree/bindings/display/bridge/chipone,icn6211.yaml
+ F: drivers/gpu/drm/bridge/chipone-icn6211.c
+
DRM DRIVER FOR FARADAY TVE200 TV ENCODER
S: Maintained
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+ DRM DRIVER FOR GENERIC USB DISPLAY
+ S: Maintained
+ W: https://github.com/notro/gud/wiki
+ T: git git://anongit.freedesktop.org/drm/drm-misc
+ F: drivers/gpu/drm/gud/
+ F: include/drm/gud.h
+
DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
S: Maintained
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
-F: Documentation/devicetree/bindings/display/ste,mcde.txt
+F: Documentation/devicetree/bindings/display/ste,mcde.yaml
F: drivers/gpu/drm/mcde/
DRM DRIVER FOR TDFX VIDEO CARDS
DRM DRIVERS FOR BRIDGE CHIPS
S: Supported
F: Documentation/devicetree/bindings/display/mediatek/
F: drivers/gpu/drm/mediatek/
S: Supported
T: git git://linuxtv.org/pinchartl/media drm/du/next
- F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
+ F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml
F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml
- F: Documentation/devicetree/bindings/display/renesas,du.txt
+ F: Documentation/devicetree/bindings/display/renesas,du.yaml
F: drivers/gpu/drm/rcar-du/
F: drivers/gpu/drm/shmobile/
F: include/linux/platform_data/shmob_drm.h
S: Supported
T: git git://anongit.freedesktop.org/drm/drm-misc
-F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
+F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
F: drivers/gpu/drm/v3d/
F: include/uapi/drm/v3d_drm.h
F: Documentation/ABI/testing/sysfs-bus-dfl*
F: Documentation/fpga/dfl.rst
F: drivers/fpga/dfl*
+F: drivers/uio/uio_dfl.c
F: include/linux/dfl.h
F: include/uapi/linux/fpga-dfl.h
F: drivers/i2c/busses/i2c-cpm.c
FREESCALE IMX / MXC FEC DRIVER
-M: Fugang Duan <fugang.duan@nxp.com>
+M: Joakim Zhang <qiangqing.zhang@nxp.com>
S: Maintained
F: Documentation/devicetree/bindings/net/fsl-fec.txt
S: Maintained
+F: Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml
F: drivers/spi/spi-fsl-qspi.c
FREESCALE QUICC ENGINE LIBRARY
S: Maintained
-F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt
+F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
F: Documentation/devicetree/bindings/soc/fsl/
F: drivers/soc/fsl/
F: include/linux/fsl/
F: drivers/hwmon/gsc-hwmon.c
F: include/linux/platform_data/gsc_hwmon.h
-GASKET DRIVER FRAMEWORK
-S: Maintained
-F: drivers/staging/gasket/
-
GCC PLUGINS
F: fs/gfs2/
F: include/uapi/linux/gfs2_ondisk.h
+GIGABYTE WMI DRIVER
+S: Maintained
+F: drivers/platform/x86/gigabyte-wmi.c
+
GNSS SUBSYSTEM
S: Maintained
F: drivers/hwmon/
F: include/linux/hwmon*.h
F: include/trace/events/hwmon*.h
+K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info)
HARDWARE RANDOM NUMBER GENERATOR CORE
T: git git://linuxtv.org/media_tree.git
F: drivers/media/usb/hdpvr/
+HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER
+S: Supported
+F: drivers/misc/hpilo.[ch]
+
HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
S: Supported
F: drivers/crypto/hisilicon/sec2/sec_crypto.h
F: drivers/crypto/hisilicon/sec2/sec_main.c
+HISILICON SPI Controller DRIVER FOR KUNPENG SOCS
+S: Maintained
+W: http://www.hisilicon.com
+F: drivers/spi/spi-hisi-kunpeng.c
+
HISILICON STAGING DRIVERS FOR HIKEY 960/970
S: Maintained
S: Maintained
W: http://www.st.com/
-F: Documentation/devicetree/bindings/iio/humidity/hts221.txt
+F: Documentation/devicetree/bindings/iio/humidity/st,hts221.yaml
F: drivers/iio/humidity/hts221*
HUAWEI ETHERNET DRIVER
IBM Power SRIOV Virtual NIC Device Driver
S: Supported
F: drivers/net/ethernet/ibm/ibmvnic.*
F: drivers/scsi/ibmvscsi/ibmvfc*
IBM Power Virtual Management Channel Driver
S: Supported
F: drivers/misc/ibmvmc.*
F: include/linux/ide.h
IDE/ATAPI DRIVERS
-S: Maintained
+S: Orphan
F: Documentation/cdrom/ide-cd.rst
F: drivers/ide/ide-cd*
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac
-F: Documentation/devicetree/bindings/iio/dac/dpot-dac.txt
+F: Documentation/devicetree/bindings/iio/dac/dpot-dac.yaml
F: drivers/iio/dac/dpot-dac.c
IIO ENVELOPE DETECTOR
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
-F: Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
+F: Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml
F: drivers/iio/adc/envelope-detector.c
IIO MULTIPLEXER
F: Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
F: drivers/iio/multiplexer/iio-mux.c
+IIO SCMI BASED DRIVER
+S: Maintained
+F: drivers/iio/common/scmi_sensors/scmi_iio.c
+
IIO SUBSYSTEM AND DRIVERS
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
S: Maintained
-F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt
-F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt
-F: Documentation/devicetree/bindings/iio/afe/voltage-divider.txt
+F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.yaml
+F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.yaml
+F: Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml
F: drivers/iio/afe/iio-rescale.c
IKANOS/ADI EAGLE ADSL USB DRIVER
S: Maintained
+F: Documentation/ABI/testing/sysfs-platform-intel-pmc
F: drivers/platform/x86/intel_pmc_core*
INTEL PMIC GPIO DRIVERS
F: drivers/platform/x86/intel-wmi-sbl-fw-update.c
INTEL WMI THUNDERBOLT FORCE POWER DRIVER
S: Maintained
F: drivers/platform/x86/intel-wmi-thunderbolt.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx
F: Documentation/x86/sgx.rst
F: arch/x86/entry/vdso/vsgx.S
+F: arch/x86/include/asm/sgx.h
F: arch/x86/include/uapi/asm/sgx.h
F: arch/x86/kernel/cpu/sgx/*
F: tools/testing/selftests/sgx/*
S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git
F: Documentation/devicetree/bindings/interconnect/
F: Documentation/driver-api/interconnect.rst
F: drivers/interconnect/
F: include/linux/interconnect-provider.h
F: include/linux/interconnect.h
+INTERRUPT COUNTER DRIVER
+F: Documentation/devicetree/bindings/counter/interrupt-counter.yaml
+F: drivers/counter/interrupt-cnt.c
+
INVENSENSE ICM-426xx IMU DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.txt
+F: Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.yaml
F: drivers/iio/gyro/mpu3050*
IOC3 ETHERNET DRIVER
F: net/sunrpc/
F: Documentation/filesystems/nfs/
+KERNEL REGRESSIONS
+S: Supported
+
KERNEL SELFTEST FRAMEWORK
F: include/keys/trusted_tpm.h
F: security/keys/trusted-keys/
+KEYS-TRUSTED-TEE
+S: Supported
+F: include/keys/trusted_tee.h
+F: security/keys/trusted-keys/trusted_tee.c
+
KEYS/KEYRINGS
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
F: drivers/hid/hid-lg-g15.c
+ LONTIUM LT8912B MIPI TO HDMI BRIDGE
+ S: Maintained
+ F: Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml
+ F: drivers/gpu/drm/bridge/lontium-lt8912b.c
+
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
F: drivers/video/fbdev/matrox/matroxfb_*
F: include/uapi/linux/matroxfb.h
+MAX15301 DRIVER
+S: Maintained
+F: Documentation/hwmon/max15301.rst
+F: drivers/hwmon/pmbus/max15301.c
+
MAX16065 HARDWARE MONITOR DRIVER
F: include/dt-bindings/*/*max77802.h
MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
S: Supported
MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
S: Supported
F: include/media/drv-intf/renesas-ceu.h
MEDIA DRIVERS FOR RENESAS - DRIF
-M: Ramesh Shanmugasundaram <rashanmu@gmail.com>
+M: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
S: Supported
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/renesas,drif.txt
+F: Documentation/devicetree/bindings/media/renesas,drif.yaml
F: drivers/media/platform/rcar_drif.c
MEDIA DRIVERS FOR RENESAS - FCP
MEDIATEK MMC/SD/SDIO DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/mmc/mtk-sd.txt
+F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml
F: drivers/mmc/host/mtk-sd.c
MEDIATEK MT76 WIRELESS LAN DRIVER
F: drivers/net/ethernet/mellanox/mlxfw/
MELLANOX HARDWARE PLATFORM SUPPORT
S: Supported
F: mm/memblock.c
MEMORY CONTROLLER DRIVERS
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
S: Supported
-F: Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
+F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
F: drivers/iio/adc/at91-sama5d2_adc.c
F: include/dt-bindings/iio/adc/at91-sama5d2_adc.h
F: include/linux/cciss*.h
F: include/uapi/linux/cciss*.h
+MICROSOFT SURFACE DTX DRIVER
+S: Maintained
+F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
+F: drivers/platform/surface/surface_dtx.c
+F: include/uapi/linux/surface_aggregator/dtx.h
+
MICROSOFT SURFACE GPE LID SUPPORT DRIVER
S: Maintained
F: drivers/platform/surface/surface_hotplug.c
+MICROSOFT SURFACE PLATFORM PROFILE DRIVER
+S: Maintained
+F: drivers/platform/surface/surface_platform_profile.c
+
MICROSOFT SURFACE PRO 3 BUTTON DRIVER
F: drivers/platform/surface/aggregator/
F: drivers/platform/surface/surface_acpi_notify.c
F: drivers/platform/surface/surface_aggregator_cdev.c
+F: drivers/platform/surface/surface_aggregator_registry.c
F: include/linux/surface_acpi_notify.h
F: include/linux/surface_aggregator/
F: include/uapi/linux/surface_aggregator/
F: include/uapi/linux/meye.h
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
-S: Maintained
+S: Orphan
F: Documentation/driver-api/serial/moxa-smartio.rst
F: drivers/tty/mxser.*
F: include/dt-bindings/mux/
F: include/linux/mux/
-MULTITECH MULTIPORT CARD (ISICOM)
-S: Orphan
-F: drivers/tty/isicom.c
-F: include/linux/isicom.h
-
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
S: Supported
T: git git://anongit.freedesktop.org/drm/drm-misc
- F: Documentation/devicetree/bindings/display/mxsfb.txt
+ F: Documentation/devicetree/bindings/display/fsl,lcdif.yaml
F: drivers/gpu/drm/mxsfb/
MYLEX DAC960 PCI RAID Controller
F: drivers/regulator/pf8x00-regulator.c
NXP PTN5150A CC LOGIC AND EXTCON DRIVER
S: Maintained
F: Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml
S: Supported
F: drivers/nfc/nxp-nci
+NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER
+S: Maintained
+F: Documentation/devicetree/bindings/media/imx8-jpeg.yaml
+F: drivers/media/platform/imx-jpeg
+
+NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
+S: Maintained
+F: Documentation/hwmon/nzxt-kraken2.rst
+F: drivers/hwmon/nzxt-kraken2.c
+
OBJAGG
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/i2c/ov2680.yaml
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml
F: drivers/media/i2c/ov2680.c
OMNIVISION OV2685 SENSOR DRIVER
PIN CONTROLLER - SAMSUNG
S: Maintained
-F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
+F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.yaml
F: drivers/iio/magnetometer/rm3100*
PNP SUPPORT
F: include/linux/powercap.h
F: kernel/configs/nopm.config
+DYNAMIC THERMAL POWER MANAGEMENT (DTPM)
+S: Supported
+B: https://bugzilla.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
+F: drivers/powercap/dtpm*
+F: include/linux/dtpm.h
+
POWER STATE COORDINATION INTERFACE (PSCI)
PRINTK
S: Maintained
S: Maintained
F: Documentation/admin-guide/media/qcom_camss.rst
-F: Documentation/devicetree/bindings/media/qcom,camss.txt
+F: Documentation/devicetree/bindings/media/*camss*
F: drivers/media/platform/qcom/camss/
QUALCOMM CORE POWER REDUCTION (CPR) AVS DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/media/i2c/rdacm2x-gmsl.yaml
+F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml
F: drivers/media/i2c/max9271.c
F: drivers/media/i2c/max9271.h
F: drivers/media/i2c/rdacm21.c
S: Supported
-F: Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
+F: Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml
F: drivers/iio/adc/rcar-gyroadc.c
RENESAS R-CAR I2C DRIVERS
S: Supported
F: drivers/net/ethernet/rocker/
-ROCKETPORT DRIVER
-S: Maintained
-W: http://www.comtrol.com
-F: Documentation/driver-api/serial/rocket.rst
-F: drivers/tty/rocket*
-
ROCKETPORT EXPRESS/INFINITY DRIVER
F: security/safesetid/
SAMSUNG AUDIO (ASoC) DRIVERS
S: Supported
F: sound/soc/samsung/
SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
S: Maintained
F: drivers/platform/x86/samsung-laptop.c
SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
F: include/media/drv-intf/s3c_camif.h
SAMSUNG S3FWRN5 NFC DRIVER
S: Maintained
F: drivers/media/i2c/s5k5baf.c
SAMSUNG S5P Security SubSystem (SSS) DRIVER
F: include/linux/platform_data/clk-s3c2410.h
SAMSUNG SPI DRIVERS
F: include/linux/arm_sdei.h
F: include/uapi/linux/arm_sdei.h
+SOFTWARE NODES
+S: Maintained
+F: drivers/base/swnode.c
+
SOFTWARE RAID (Multiple Disks) SUPPORT
SPI NOR SUBSYSTEM
S: Maintained
W: http://www.linux-mtd.infradead.org/
S: Maintained
W: http://www.st.com/
-F: Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
+F: Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml
F: drivers/iio/imu/st_lsm6dsx/
ST MIPID02 CSI-2 TO PARALLEL BRIDGE DRIVER
S: Maintained
F: drivers/i2c/busses/i2c-stm32*
+ST STPDDC60 DRIVER
+S: Maintained
+F: Documentation/hwmon/stpddc60.rst
+F: drivers/hwmon/pmbus/stpddc60.c
+
ST VL53L0X ToF RANGER(I2C) IIO DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/iio/proximity/vl53l0x.txt
+F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml
F: drivers/iio/proximity/vl53l0x-i2c.c
STABLE BRANCH
S: Maintained
F: drivers/staging/media/atomisp/
-STAGING - COMEDI
-S: Odd Fixes
-F: drivers/staging/comedi/
-
STAGING - FIELDBUS SUBSYSTEM
S: Maintained
SYNOPSYS DESIGNWARE AXI DMAC DRIVER
S: Maintained
-F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt
+F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
F: drivers/dma/dw-axi-dmac/
SYNOPSYS DESIGNWARE DMAC DRIVER
S: Supported
-F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
+F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml
F: drivers/iio/dac/ti-dac7612.c
TEXAS INSTRUMENTS DMA DRIVERS
S: Odd Fixes
F: drivers/gpio/gpio-thunderx.c
+TI ADS131E0X ADC SERIES DRIVER
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml
+F: drivers/iio/adc/ti-ads131e08.c
+
TI AM437X VPFE DRIVER
VSPRINTF
S: Maintained
ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
S: Maintained
F: Documentation/admin-guide/blockdev/zram.rst
ZSMALLOC COMPRESSED SLAB MEMORY ALLOCATOR
S: Maintained
F: Documentation/vm/zsmalloc.rst
#include "amdgpu.h"
#include "amdgpu_gfx.h"
#include "amdgpu_psp.h"
- #include "amdgpu_smu.h"
#include "nv.h"
#include "nvd.h"
#define mmGC_THROTTLE_CTRL_Sienna_Cichlid 0x2030
#define mmGC_THROTTLE_CTRL_Sienna_Cichlid_BASE_IDX 0
+ #define GFX_RLCG_GC_WRITE_OLD (0x8 << 28)
+ #define GFX_RLCG_GC_WRITE (0x0 << 28)
+ #define GFX_RLCG_GC_READ (0x1 << 28)
+ #define GFX_RLCG_MMHUB_WRITE (0x2 << 28)
+
MODULE_FIRMWARE("amdgpu/navi10_ce.bin");
MODULE_FIRMWARE("amdgpu/navi10_pfp.bin");
MODULE_FIRMWARE("amdgpu/navi10_me.bin");
SOC15_REG_GOLDEN_VALUE(GC, 0, mmUTCL1_CTRL, 0xffffffff, 0x00800000)
};
- static void gfx_v10_rlcg_wreg(struct amdgpu_device *adev, u32 offset, u32 v)
+ static bool gfx_v10_is_rlcg_rw(struct amdgpu_device *adev, u32 offset, uint32_t *flag, bool write)
+ {
+ /* always programed by rlcg, only for gc */
+ if (offset == SOC15_REG_OFFSET(GC, 0, mmRLC_CSIB_ADDR_HI) ||
+ offset == SOC15_REG_OFFSET(GC, 0, mmRLC_CSIB_ADDR_LO) ||
+ offset == SOC15_REG_OFFSET(GC, 0, mmRLC_CSIB_LENGTH) ||
+ offset == SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_CNTL) ||
+ offset == SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX) ||
+ offset == SOC15_REG_OFFSET(GC, 0, mmCP_ME_CNTL)) {
+ if (!amdgpu_sriov_reg_indirect_gc(adev))
+ *flag = GFX_RLCG_GC_WRITE_OLD;
+ else
+ *flag = write ? GFX_RLCG_GC_WRITE : GFX_RLCG_GC_READ;
+
+ return true;
+ }
+
+ /* currently support gc read/write, mmhub write */
+ if (offset >= SOC15_REG_OFFSET(GC, 0, mmSDMA0_DEC_START) &&
+ offset <= SOC15_REG_OFFSET(GC, 0, mmRLC_GTS_OFFSET_MSB)) {
+ if (amdgpu_sriov_reg_indirect_gc(adev))
+ *flag = write ? GFX_RLCG_GC_WRITE : GFX_RLCG_GC_READ;
+ else
+ return false;
+ } else {
+ if (amdgpu_sriov_reg_indirect_mmhub(adev))
+ *flag = GFX_RLCG_MMHUB_WRITE;
+ else
+ return false;
+ }
+
+ return true;
+ }
+
+ static u32 gfx_v10_rlcg_rw(struct amdgpu_device *adev, u32 offset, u32 v, uint32_t flag)
{
static void *scratch_reg0;
static void *scratch_reg1;
+ static void *scratch_reg2;
+ static void *scratch_reg3;
static void *spare_int;
+ static uint32_t grbm_cntl;
+ static uint32_t grbm_idx;
uint32_t i = 0;
uint32_t retries = 50000;
+ u32 ret = 0;
+
+ scratch_reg0 = adev->rmmio +
+ (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG0_BASE_IDX] + mmSCRATCH_REG0) * 4;
+ scratch_reg1 = adev->rmmio +
+ (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG1) * 4;
+ scratch_reg2 = adev->rmmio +
+ (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG0_BASE_IDX] + mmSCRATCH_REG2) * 4;
+ scratch_reg3 = adev->rmmio +
+ (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG3) * 4;
+ spare_int = adev->rmmio +
+ (adev->reg_offset[GC_HWIP][0][mmRLC_SPARE_INT_BASE_IDX] + mmRLC_SPARE_INT) * 4;
+
+ grbm_cntl = adev->reg_offset[GC_HWIP][0][mmGRBM_GFX_CNTL_BASE_IDX] + mmGRBM_GFX_CNTL;
+ grbm_idx = adev->reg_offset[GC_HWIP][0][mmGRBM_GFX_INDEX_BASE_IDX] + mmGRBM_GFX_INDEX;
+
+ if (offset == grbm_cntl || offset == grbm_idx) {
+ if (offset == grbm_cntl)
+ writel(v, scratch_reg2);
+ else if (offset == grbm_idx)
+ writel(v, scratch_reg3);
+
+ writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
+ } else {
+ writel(v, scratch_reg0);
+ writel(offset | flag, scratch_reg1);
+ writel(1, spare_int);
+ for (i = 0; i < retries; i++) {
+ u32 tmp;
+
+ tmp = readl(scratch_reg1);
+ if (!(tmp & flag))
+ break;
+
+ udelay(10);
+ }
+
+ if (i >= retries)
+ pr_err("timeout: rlcg program reg:0x%05x failed !\n", offset);
+ }
- scratch_reg0 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG0_BASE_IDX] + mmSCRATCH_REG0)*4;
- scratch_reg1 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG1)*4;
- spare_int = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmRLC_SPARE_INT_BASE_IDX] + mmRLC_SPARE_INT)*4;
+ ret = readl(scratch_reg0);
+
+ return ret;
+ }
+
+ static void gfx_v10_rlcg_wreg(struct amdgpu_device *adev, u32 offset, u32 value, u32 flag)
+ {
+ uint32_t rlcg_flag;
+
+ if (amdgpu_sriov_fullaccess(adev) &&
+ gfx_v10_is_rlcg_rw(adev, offset, &rlcg_flag, 1)) {
+ gfx_v10_rlcg_rw(adev, offset, value, rlcg_flag);
- if (amdgpu_sriov_runtime(adev)) {
- pr_err("shouldn't call rlcg write register during runtime\n");
return;
}
+ if (flag & AMDGPU_REGS_NO_KIQ)
+ WREG32_NO_KIQ(offset, value);
+ else
+ WREG32(offset, value);
+ }
- writel(v, scratch_reg0);
- writel(offset | 0x80000000, scratch_reg1);
- writel(1, spare_int);
- for (i = 0; i < retries; i++) {
- u32 tmp;
+ static u32 gfx_v10_rlcg_rreg(struct amdgpu_device *adev, u32 offset, u32 flag)
+ {
+ uint32_t rlcg_flag;
- tmp = readl(scratch_reg1);
- if (!(tmp & 0x80000000))
- break;
+ if (amdgpu_sriov_fullaccess(adev) &&
+ gfx_v10_is_rlcg_rw(adev, offset, &rlcg_flag, 0))
+ return gfx_v10_rlcg_rw(adev, offset, 0, rlcg_flag);
- udelay(10);
- }
+ if (flag & AMDGPU_REGS_NO_KIQ)
+ return RREG32_NO_KIQ(offset);
+ else
+ return RREG32(offset);
- if (i >= retries)
- pr_err("timeout: rlcg program reg:0x%05x failed !\n", offset);
+ return 0;
}
static const struct soc15_reg_golden golden_settings_gc_10_1_nv14[] =
SOC15_REG_GOLDEN_VALUE(GC, 0, mmCPF_GCR_CNTL, 0x0007ffff, 0x0000c000),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0x00000280, 0x00000280),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0x07800000, 0x00800000),
- SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x00001d00, 0x00000500),
+ SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Sienna_Cichlid, 0x00001d00, 0x00000500),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmGE_PC_CNTL, 0x003c0000, 0x00280400),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2A_ADDR_MATCH_MASK, 0xffffffff, 0xffffffcf),
SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_ADDR_MATCH_MASK, 0xffffffff, 0xffffffcf),
sprintf(ring->name, "gfx_%d.%d.%d", ring->me, ring->pipe, ring->queue);
irq_type = AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP + ring->pipe;
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->gfx.eop_irq, irq_type,
- AMDGPU_RING_PRIO_DEFAULT);
+ r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq, irq_type,
+ AMDGPU_RING_PRIO_DEFAULT, NULL);
if (r)
return r;
return 0;
hw_prio = amdgpu_gfx_is_high_priority_compute_queue(adev, ring) ?
AMDGPU_GFX_PIPE_PRIO_HIGH : AMDGPU_GFX_PIPE_PRIO_NORMAL;
/* type-2 packets are deprecated on MEC, use type-3 instead */
- r = amdgpu_ring_init(adev, ring, 1024,
- &adev->gfx.eop_irq, irq_type, hw_prio);
+ r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq, irq_type,
+ hw_prio, NULL);
if (r)
return r;
* loaded firstly, so in direct type, it has to load smc ucode
* here before rlc.
*/
- if (adev->smu.ppt_funcs != NULL && !(adev->flags & AMD_IS_APU)) {
- r = smu_load_microcode(&adev->smu);
+ if (!(adev->flags & AMD_IS_APU)) {
+ r = amdgpu_pm_load_smu_firmware(adev, NULL);
if (r)
return r;
-
- r = smu_check_fw_status(&adev->smu);
- if (r) {
- pr_err("SMC firmware status is not correct\n");
- return r;
- }
}
gfx_v10_0_disable_gpa_mode(adev);
}
.start = gfx_v10_0_rlc_start,
.update_spm_vmid = gfx_v10_0_update_spm_vmid,
.rlcg_wreg = gfx_v10_rlcg_wreg,
+ .rlcg_rreg = gfx_v10_rlcg_rreg,
.is_rlcg_access_range = gfx_v10_0_is_rlcg_access_range,
};
#include "dc/inc/hw/dmcu.h"
#include "dc/inc/hw/abm.h"
#include "dc/dc_dmub_srv.h"
+ #include "dc/dc_edid_parser.h"
#include "amdgpu_dm_trace.h"
#include "vid.h"
#include <drm/drm_edid.h>
#include <drm/drm_vblank.h>
#include <drm/drm_audio_component.h>
- #include <drm/drm_hdcp.h>
#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
* DOC: overview
*
* The AMDgpu display manager, **amdgpu_dm** (or even simpler,
- * **dm**) sits between DRM and DC. It acts as a liason, converting DRM
+ * **dm**) sits between DRM and DC. It acts as a liaison, converting DRM
* requests into DC requests, and DC responses into DRM responses.
*
* The root control structure is &struct amdgpu_display_manager.
/* basic init/fini API */
static int amdgpu_dm_init(struct amdgpu_device *adev);
static void amdgpu_dm_fini(struct amdgpu_device *adev);
+ static bool is_freesync_video_mode(const struct drm_display_mode *mode, struct amdgpu_dm_connector *aconnector);
static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
{
static const struct drm_format_info *
amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
+ static bool
+ is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
+ struct drm_crtc_state *new_crtc_state);
/*
* dm_vblank_get_counter
*
dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
}
+ static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
+ struct dm_crtc_state *new_state)
+ {
+ if (new_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)
+ return true;
+ else if (amdgpu_dm_vrr_active(old_state) != amdgpu_dm_vrr_active(new_state))
+ return true;
+ else
+ return false;
+ }
+
/**
* dm_pflip_high_irq() - Handle pageflip interrupt
* @interrupt_params: ignored
/* IRQ could occur when in initial stage */
/* TODO work and BO cleanup */
if (amdgpu_crtc == NULL) {
- DRM_DEBUG_DRIVER("CRTC is null, returning.\n");
+ DC_LOG_PFLIP("CRTC is null, returning.\n");
return;
}
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
- DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
+ DC_LOG_PFLIP("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
amdgpu_crtc->pflip_status,
AMDGPU_FLIP_SUBMITTED,
amdgpu_crtc->crtc_id,
amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
- amdgpu_crtc->crtc_id, amdgpu_crtc,
- vrr_active, (int) !e);
+ DC_LOG_PFLIP("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
+ amdgpu_crtc->crtc_id, amdgpu_crtc,
+ vrr_active, (int) !e);
}
static void dm_vupdate_high_irq(void *interrupt_params)
struct common_irq_params *irq_params = interrupt_params;
struct amdgpu_device *adev = irq_params->adev;
struct amdgpu_crtc *acrtc;
+ struct drm_device *drm_dev;
+ struct drm_vblank_crtc *vblank;
+ ktime_t frame_duration_ns, previous_timestamp;
unsigned long flags;
int vrr_active;
if (acrtc) {
vrr_active = amdgpu_dm_vrr_active_irq(acrtc);
+ drm_dev = acrtc->base.dev;
+ vblank = &drm_dev->vblank[acrtc->base.index];
+ previous_timestamp = atomic64_read(&irq_params->previous_timestamp);
+ frame_duration_ns = vblank->time - previous_timestamp;
+
+ if (frame_duration_ns > 0) {
+ trace_amdgpu_refresh_rate_track(acrtc->base.index,
+ frame_duration_ns,
+ ktime_divns(NSEC_PER_SEC, frame_duration_ns));
+ atomic64_set(&irq_params->previous_timestamp, vblank->time);
+ }
- DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n",
+ DC_LOG_VBLANK("crtc:%d, vupdate-vrr:%d\n",
acrtc->crtc_id,
vrr_active);
vrr_active = amdgpu_dm_vrr_active_irq(acrtc);
- DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
+ DC_LOG_VBLANK("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
vrr_active, acrtc->dm_irq_params.active_planes);
/**
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
+ /**
+ * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
+ * DCN generation ASICs
+ * @interrupt params - interrupt parameters
+ *
+ * Used to set crc window/read out crc value at vertical line 0 position
+ */
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
+ {
+ struct common_irq_params *irq_params = interrupt_params;
+ struct amdgpu_device *adev = irq_params->adev;
+ struct amdgpu_crtc *acrtc;
+
+ acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VLINE0);
+
+ if (!acrtc)
+ return;
+
+ amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base);
+ }
+ #endif
+ #endif
+
static int dm_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
}
#if defined(CONFIG_DRM_AMD_DC_DCN)
+ #define DMUB_TRACE_MAX_READ 64
+ static void dm_dmub_trace_high_irq(void *interrupt_params)
+ {
+ struct common_irq_params *irq_params = interrupt_params;
+ struct amdgpu_device *adev = irq_params->adev;
+ struct amdgpu_display_manager *dm = &adev->dm;
+ struct dmcub_trace_buf_entry entry = { 0 };
+ uint32_t count = 0;
+
+ do {
+ if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) {
+ trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count,
+ entry.param0, entry.param1);
+
+ DRM_DEBUG_DRIVER("trace_code:%u, tick_count:%u, param0:%u, param1:%u\n",
+ entry.trace_code, entry.tick_count, entry.param0, entry.param1);
+ } else
+ break;
+
+ count++;
+
+ } while (count <= DMUB_TRACE_MAX_READ);
+
+ ASSERT(count <= DMUB_TRACE_MAX_READ);
+ }
+
static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
{
uint64_t pt_base;
if (vblank_work->enable)
dm->active_vblank_irq_count++;
- else
+ else if(dm->active_vblank_irq_count)
dm->active_vblank_irq_count--;
+ dc_allow_idle_optimizations(dm->dc, dm->active_vblank_irq_count == 0);
- dc_allow_idle_optimizations(
- dm->dc, dm->active_vblank_irq_count == 0 ? true : false);
-
- DRM_DEBUG_DRIVER("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
-
+ DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
mutex_unlock(&dm->dc_lock);
}
init_data.flags.power_down_display_on_boot = true;
+ INIT_LIST_HEAD(&adev->dm.da_list);
/* Display Core create. */
adev->dm.dc = dc_create(&init_data);
dc_init_callbacks(adev->dm.dc, &init_params);
}
+ #endif
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
#endif
if (amdgpu_dm_initialize_drm_device(adev)) {
DRM_ERROR(
amdgpu_dm_destroy_drm_device(&adev->dm);
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ if (adev->dm.crc_rd_wrk) {
+ flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
+ kfree(adev->dm.crc_rd_wrk);
+ adev->dm.crc_rd_wrk = NULL;
+ }
+ #endif
#ifdef CONFIG_DRM_AMD_DC_HDCP
if (adev->dm.hdcp_workqueue) {
hdcp_destroy(&adev->dev->kobj, adev->dm.hdcp_workqueue);
if (adev->dm.dc)
dc_deinit_callbacks(adev->dm.dc);
#endif
+
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (adev->dm.vblank_workqueue) {
+ adev->dm.vblank_workqueue->dm = NULL;
+ kfree(adev->dm.vblank_workqueue);
+ adev->dm.vblank_workqueue = NULL;
+ }
+ #endif
+
if (adev->dm.dc->ctx->dmub_srv) {
dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv);
adev->dm.dc->ctx->dmub_srv = NULL;
if (acrtc && state->stream_status[i].plane_count != 0) {
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
- DRM_DEBUG("crtc %d - vupdate irq %sabling: r=%d\n",
- acrtc->crtc_id, enable ? "en" : "dis", rc);
+ DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
+ acrtc->crtc_id, enable ? "en" : "dis", rc);
if (rc)
DRM_WARN("Failed to %s pflip interrupts\n",
enable ? "enable" : "disable");
return ret;
}
+ #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ amdgpu_dm_crtc_secure_display_suspend(adev);
+ #endif
WARN_ON(adev->dm.cached_state);
adev->dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev));
dm->cached_state = NULL;
+ #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ amdgpu_dm_crtc_secure_display_resume(adev);
+ #endif
+
amdgpu_dm_irq_resume_late(adev);
amdgpu_dm_smu_write_watermarks_table(adev);
struct dc_interrupt_params int_params = {0};
int r;
int i;
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ static const unsigned int vrtl_int_srcid[] = {
+ DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
+ DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
+ DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
+ DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
+ DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
+ DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
+ };
+ #endif
int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
adev, &int_params, dm_crtc_high_irq, c_irq_params);
}
+ /* Use otg vertical line interrupt */
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
+ vrtl_int_srcid[i], &adev->vline0_irq);
+
+ if (r) {
+ DRM_ERROR("Failed to add vline0 irq id!\n");
+ return r;
+ }
+
+ int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+ int_params.irq_source =
+ dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0);
+
+ if (int_params.irq_source == DC_IRQ_SOURCE_INVALID) {
+ DRM_ERROR("Failed to register vline0 irq %d!\n", vrtl_int_srcid[i]);
+ break;
+ }
+
+ c_irq_params = &adev->dm.vline0_params[int_params.irq_source
+ - DC_IRQ_SOURCE_DC1_VLINE0];
+
+ c_irq_params->adev = adev;
+ c_irq_params->irq_src = int_params.irq_source;
+
+ amdgpu_dm_irq_register_interrupt(adev, &int_params,
+ dm_dcn_vertical_interrupt0_high_irq, c_irq_params);
+ }
+ #endif
+
/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
* the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
* to trigger at end of each vblank, regardless of state of the lock,
}
+ if (dc->ctx->dmub_srv) {
+ i = DCN_1_0__SRCID__DMCUB_OUTBOX_HIGH_PRIORITY_READY_INT;
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->dmub_trace_irq);
+
+ if (r) {
+ DRM_ERROR("Failed to add dmub trace irq id!\n");
+ return r;
+ }
+
+ int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+ int_params.irq_source =
+ dc_interrupt_to_irq_source(dc, i, 0);
+
+ c_irq_params = &adev->dm.dmub_trace_params[0];
+
+ c_irq_params->adev = adev;
+ c_irq_params->irq_src = int_params.irq_source;
+
+ amdgpu_dm_irq_register_interrupt(adev, &int_params,
+ dm_dmub_trace_high_irq, c_irq_params);
+ }
+
/* HPD */
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
&adev->hpd_irq);
if (modifier == DRM_FORMAT_MOD_LINEAR)
return true;
- /*
- * The arbitrary tiling support for multiplane formats has not been hooked
- * up.
- */
- if (info->num_planes > 1)
- return false;
-
/*
* For D swizzle the canonical modifier depends on the bpp, so check
* it here.
/* Per radeonsi comments 16/64 bpp are more complicated. */
if (info->cpp[0] != 4)
return false;
+ /* We support multi-planar formats, but not when combined with
+ * additional DCC metadata planes. */
+ if (info->num_planes > 1)
+ return false;
}
return true;
AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
- AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
+ AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
add_modifier(mods, size, capacity, AMD_FMT_MOD |
AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
- AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
+ AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
add_modifier(mods, size, capacity, AMD_FMT_MOD |
AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
const struct drm_framebuffer *fb = plane_state->fb;
const struct amdgpu_framebuffer *afb =
to_amdgpu_framebuffer(plane_state->fb);
- struct drm_format_name_buf format_name;
int ret;
memset(plane_info, 0, sizeof(*plane_info));
break;
default:
DRM_ERROR(
- "Unsupported screen format %s\n",
- drm_get_format_name(fb->format->format, &format_name));
+ "Unsupported screen format %p4cc\n",
+ &fb->format->format);
return -EINVAL;
}
stream->src = src;
stream->dst = dst;
- DRM_DEBUG_DRIVER("Destination Rectangle x:%d y:%d width:%d height:%d\n",
- dst.x, dst.y, dst.width, dst.height);
+ DRM_DEBUG_KMS("Destination Rectangle x:%d y:%d width:%d height:%d\n",
+ dst.x, dst.y, dst.width, dst.height);
}
timing_out->hdmi_vic = hv_frame.vic;
}
- timing_out->h_addressable = mode_in->crtc_hdisplay;
- timing_out->h_total = mode_in->crtc_htotal;
- timing_out->h_sync_width =
- mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
- timing_out->h_front_porch =
- mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
- timing_out->v_total = mode_in->crtc_vtotal;
- timing_out->v_addressable = mode_in->crtc_vdisplay;
- timing_out->v_front_porch =
- mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
- timing_out->v_sync_width =
- mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
- timing_out->pix_clk_100hz = mode_in->crtc_clock * 10;
+ if (is_freesync_video_mode(mode_in, aconnector)) {
+ timing_out->h_addressable = mode_in->hdisplay;
+ timing_out->h_total = mode_in->htotal;
+ timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start;
+ timing_out->h_front_porch = mode_in->hsync_start - mode_in->hdisplay;
+ timing_out->v_total = mode_in->vtotal;
+ timing_out->v_addressable = mode_in->vdisplay;
+ timing_out->v_front_porch = mode_in->vsync_start - mode_in->vdisplay;
+ timing_out->v_sync_width = mode_in->vsync_end - mode_in->vsync_start;
+ timing_out->pix_clk_100hz = mode_in->clock * 10;
+ } else {
+ timing_out->h_addressable = mode_in->crtc_hdisplay;
+ timing_out->h_total = mode_in->crtc_htotal;
+ timing_out->h_sync_width = mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
+ timing_out->h_front_porch = mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
+ timing_out->v_total = mode_in->crtc_vtotal;
+ timing_out->v_addressable = mode_in->crtc_vdisplay;
+ timing_out->v_front_porch = mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
+ timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
+ timing_out->pix_clk_100hz = mode_in->crtc_clock * 10;
+ }
+
timing_out->aspect_ratio = get_aspect_ratio(mode_in);
stream->output_color_space = get_output_color_space(timing_out);
static void set_multisync_trigger_params(
struct dc_stream_state *stream)
{
+ struct dc_stream_state *master = NULL;
+
if (stream->triggered_crtc_reset.enabled) {
- stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_RISING;
- stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_LINE;
+ master = stream->triggered_crtc_reset.event_source;
+ stream->triggered_crtc_reset.event =
+ master->timing.flags.VSYNC_POSITIVE_POLARITY ?
+ CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING;
+ stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL;
}
}
static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
{
int i = 0;
+ struct dc_stream_state *stream;
if (context->stream_count < 2)
return;
* crtc_sync_master.multi_sync_enabled flag
* For now it's set to false
*/
- set_multisync_trigger_params(context->streams[i]);
}
+
set_master_stream(context->streams, context->stream_count);
+
+ for (i = 0; i < context->stream_count ; i++) {
+ stream = context->streams[i];
+
+ if (!stream)
+ continue;
+
+ set_multisync_trigger_params(stream);
+ }
+ }
+
+ static struct drm_display_mode *
+ get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector,
+ bool use_probed_modes)
+ {
+ struct drm_display_mode *m, *m_pref = NULL;
+ u16 current_refresh, highest_refresh;
+ struct list_head *list_head = use_probed_modes ?
+ &aconnector->base.probed_modes :
+ &aconnector->base.modes;
+
+ if (aconnector->freesync_vid_base.clock != 0)
+ return &aconnector->freesync_vid_base;
+
+ /* Find the preferred mode */
+ list_for_each_entry (m, list_head, head) {
+ if (m->type & DRM_MODE_TYPE_PREFERRED) {
+ m_pref = m;
+ break;
+ }
+ }
+
+ if (!m_pref) {
+ /* Probably an EDID with no preferred mode. Fallback to first entry */
+ m_pref = list_first_entry_or_null(
+ &aconnector->base.modes, struct drm_display_mode, head);
+ if (!m_pref) {
+ DRM_DEBUG_DRIVER("No preferred mode found in EDID\n");
+ return NULL;
+ }
+ }
+
+ highest_refresh = drm_mode_vrefresh(m_pref);
+
+ /*
+ * Find the mode with highest refresh rate with same resolution.
+ * For some monitors, preferred mode is not the mode with highest
+ * supported refresh rate.
+ */
+ list_for_each_entry (m, list_head, head) {
+ current_refresh = drm_mode_vrefresh(m);
+
+ if (m->hdisplay == m_pref->hdisplay &&
+ m->vdisplay == m_pref->vdisplay &&
+ highest_refresh < current_refresh) {
+ highest_refresh = current_refresh;
+ m_pref = m;
+ }
+ }
+
+ aconnector->freesync_vid_base = *m_pref;
+ return m_pref;
+ }
+
+ static bool is_freesync_video_mode(const struct drm_display_mode *mode,
+ struct amdgpu_dm_connector *aconnector)
+ {
+ struct drm_display_mode *high_mode;
+ int timing_diff;
+
+ high_mode = get_highest_refresh_rate_mode(aconnector, false);
+ if (!high_mode || !mode)
+ return false;
+
+ timing_diff = high_mode->vtotal - mode->vtotal;
+
+ if (high_mode->clock == 0 || high_mode->clock != mode->clock ||
+ high_mode->hdisplay != mode->hdisplay ||
+ high_mode->vdisplay != mode->vdisplay ||
+ high_mode->hsync_start != mode->hsync_start ||
+ high_mode->hsync_end != mode->hsync_end ||
+ high_mode->htotal != mode->htotal ||
+ high_mode->hskew != mode->hskew ||
+ high_mode->vscan != mode->vscan ||
+ high_mode->vsync_start - mode->vsync_start != timing_diff ||
+ high_mode->vsync_end - mode->vsync_end != timing_diff)
+ return false;
+ else
+ return true;
}
static struct dc_stream_state *
dm_state ? &dm_state->base : NULL;
struct dc_stream_state *stream = NULL;
struct drm_display_mode mode = *drm_mode;
+ struct drm_display_mode saved_mode;
+ struct drm_display_mode *freesync_mode = NULL;
bool native_mode_found = false;
- bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false;
+ bool recalculate_timing = dm_state ? (dm_state->scaling != RMX_OFF) : false;
int mode_refresh;
int preferred_refresh = 0;
#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t link_bandwidth_kbps;
#endif
struct dc_sink *sink = NULL;
+
+ memset(&saved_mode, 0, sizeof(saved_mode));
+
if (aconnector == NULL) {
DRM_ERROR("aconnector is NULL!\n");
return stream;
*/
DRM_DEBUG_DRIVER("No preferred mode found\n");
} else {
- decide_crtc_timing_for_drm_display_mode(
+ recalculate_timing |= amdgpu_freesync_vid_mode &&
+ is_freesync_video_mode(&mode, aconnector);
+ if (recalculate_timing) {
+ freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
+ saved_mode = mode;
+ mode = *freesync_mode;
+ } else {
+ decide_crtc_timing_for_drm_display_mode(
&mode, preferred_mode,
dm_state ? (dm_state->scaling != RMX_OFF) : false);
+ }
+
preferred_refresh = drm_mode_vrefresh(preferred_mode);
}
- if (!dm_state)
+ if (recalculate_timing)
+ drm_mode_set_crtcinfo(&saved_mode, 0);
+ else if (!dm_state)
drm_mode_set_crtcinfo(&mode, 0);
- /*
+ /*
* If scaling is enabled and refresh rate didn't change
* we copy the vic and polarities of the old timings
*/
- if (!scale || mode_refresh != preferred_refresh)
- fill_stream_properties_from_drm_display_mode(stream,
- &mode, &aconnector->base, con_state, NULL, requested_bpc);
+ if (!recalculate_timing || mode_refresh != preferred_refresh)
+ fill_stream_properties_from_drm_display_mode(
+ stream, &mode, &aconnector->base, con_state, NULL,
+ requested_bpc);
else
- fill_stream_properties_from_drm_display_mode(stream,
- &mode, &aconnector->base, con_state, old_stream, requested_bpc);
+ fill_stream_properties_from_drm_display_mode(
+ stream, &mode, &aconnector->base, con_state, old_stream,
+ requested_bpc);
stream->timing.flags.DSC = 0;
state->abm_level = cur->abm_level;
state->vrr_supported = cur->vrr_supported;
state->freesync_config = cur->freesync_config;
- state->crc_src = cur->crc_src;
state->cm_has_degamma = cur->cm_has_degamma;
state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
-
/* TODO Duplicate dc_stream after objects are stream object is flattened */
return &state->base;
}
+ #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
+ {
+ crtc_debugfs_init(crtc);
+
+ return 0;
+ }
+ #endif
+
static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
{
enum dc_irq_source irq_source;
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
- DRM_DEBUG_DRIVER("crtc %d - vupdate irq %sabling: r=%d\n",
- acrtc->crtc_id, enable ? "en" : "dis", rc);
+ DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
+ acrtc->crtc_id, enable ? "en" : "dis", rc);
return rc;
}
.enable_vblank = dm_enable_vblank,
.disable_vblank = dm_disable_vblank,
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ .late_register = amdgpu_dm_crtc_late_register,
+ #endif
};
static enum drm_connector_status
} while (stream == NULL && requested_bpc >= 6);
+ if (dc_result == DC_FAIL_ENC_VALIDATE && !aconnector->force_yuv420_output) {
+ DRM_DEBUG_KMS("Retry forcing YCbCr420 encoding\n");
+
+ aconnector->force_yuv420_output = true;
+ stream = create_validate_stream_for_sink(aconnector, drm_mode,
+ dm_state, old_stream);
+ aconnector->force_yuv420_output = false;
+ }
+
return stream;
}
int r;
if (!new_state->fb) {
- DRM_DEBUG_DRIVER("No FB bound\n");
+ DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
- /* If completely outside of screen, viewport_width and/or viewport_height will be negative,
- * which is still OK to satisfy the condition below, thereby also covering these cases
- * (when plane is completely outside of screen).
- * x2 for width is because of pipe-split.
- */
- if (viewport_width < MIN_VIEWPORT_SIZE*2 || viewport_height < MIN_VIEWPORT_SIZE)
+ if (viewport_width < 0 || viewport_height < 0) {
+ DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
+ return -EINVAL;
+ } else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
+ DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
+ return -EINVAL;
+ } else if (viewport_height < MIN_VIEWPORT_SIZE) {
+ DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
return -EINVAL;
+ }
+
}
/* Get min/max allowed scaling factors from plane caps. */
}
static int dm_plane_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
+ struct drm_atomic_state *state)
{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+ plane);
struct amdgpu_device *adev = drm_to_adev(plane->dev);
struct dc *dc = adev->dm.dc;
struct dm_plane_state *dm_plane_state;
struct drm_crtc_state *new_crtc_state;
int ret;
- trace_amdgpu_dm_plane_atomic_check(state);
+ trace_amdgpu_dm_plane_atomic_check(new_plane_state);
- dm_plane_state = to_dm_plane_state(state);
+ dm_plane_state = to_dm_plane_state(new_plane_state);
if (!dm_plane_state->dc_state)
return 0;
new_crtc_state =
- drm_atomic_get_new_crtc_state(state->state, state->crtc);
+ drm_atomic_get_new_crtc_state(state,
+ new_plane_state->crtc);
if (!new_crtc_state)
return -EINVAL;
- ret = dm_plane_helper_check_state(state, new_crtc_state);
+ ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
if (ret)
return ret;
- ret = fill_dc_scaling_info(state, &scaling_info);
+ ret = fill_dc_scaling_info(new_plane_state, &scaling_info);
if (ret)
return ret;
}
static int dm_plane_atomic_async_check(struct drm_plane *plane,
- struct drm_plane_state *new_plane_state)
+ struct drm_atomic_state *state)
{
/* Only support async updates on cursor planes. */
if (plane->type != DRM_PLANE_TYPE_CURSOR)
}
static void dm_plane_atomic_async_update(struct drm_plane *plane,
- struct drm_plane_state *new_state)
+ struct drm_atomic_state *state)
{
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+ plane);
struct drm_plane_state *old_state =
- drm_atomic_get_old_plane_state(new_state->state, plane);
+ drm_atomic_get_old_plane_state(state, plane);
trace_amdgpu_dm_atomic_update_cursor(new_state);
*/
drm_mode_sort(&connector->probed_modes);
amdgpu_dm_get_native_mode(connector);
+
+ /* Freesync capabilities are reset by calling
+ * drm_add_edid_modes() and need to be
+ * restored here.
+ */
+ amdgpu_dm_update_freesync_caps(connector, edid);
} else {
amdgpu_dm_connector->num_modes = 0;
}
}
+ static bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector,
+ struct drm_display_mode *mode)
+ {
+ struct drm_display_mode *m;
+
+ list_for_each_entry (m, &aconnector->base.probed_modes, head) {
+ if (drm_mode_equal(m, mode))
+ return true;
+ }
+
+ return false;
+ }
+
+ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
+ {
+ const struct drm_display_mode *m;
+ struct drm_display_mode *new_mode;
+ uint i;
+ uint32_t new_modes_count = 0;
+
+ /* Standard FPS values
+ *
+ * 23.976 - TV/NTSC
+ * 24 - Cinema
+ * 25 - TV/PAL
+ * 29.97 - TV/NTSC
+ * 30 - TV/NTSC
+ * 48 - Cinema HFR
+ * 50 - TV/PAL
+ * 60 - Commonly used
+ * 48,72,96 - Multiples of 24
+ */
+ const uint32_t common_rates[] = { 23976, 24000, 25000, 29970, 30000,
+ 48000, 50000, 60000, 72000, 96000 };
+
+ /*
+ * Find mode with highest refresh rate with the same resolution
+ * as the preferred mode. Some monitors report a preferred mode
+ * with lower resolution than the highest refresh rate supported.
+ */
+
+ m = get_highest_refresh_rate_mode(aconnector, true);
+ if (!m)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(common_rates); i++) {
+ uint64_t target_vtotal, target_vtotal_diff;
+ uint64_t num, den;
+
+ if (drm_mode_vrefresh(m) * 1000 < common_rates[i])
+ continue;
+
+ if (common_rates[i] < aconnector->min_vfreq * 1000 ||
+ common_rates[i] > aconnector->max_vfreq * 1000)
+ continue;
+
+ num = (unsigned long long)m->clock * 1000 * 1000;
+ den = common_rates[i] * (unsigned long long)m->htotal;
+ target_vtotal = div_u64(num, den);
+ target_vtotal_diff = target_vtotal - m->vtotal;
+
+ /* Check for illegal modes */
+ if (m->vsync_start + target_vtotal_diff < m->vdisplay ||
+ m->vsync_end + target_vtotal_diff < m->vsync_start ||
+ m->vtotal + target_vtotal_diff < m->vsync_end)
+ continue;
+
+ new_mode = drm_mode_duplicate(aconnector->base.dev, m);
+ if (!new_mode)
+ goto out;
+
+ new_mode->vtotal += (u16)target_vtotal_diff;
+ new_mode->vsync_start += (u16)target_vtotal_diff;
+ new_mode->vsync_end += (u16)target_vtotal_diff;
+ new_mode->type &= ~DRM_MODE_TYPE_PREFERRED;
+ new_mode->type |= DRM_MODE_TYPE_DRIVER;
+
+ if (!is_duplicate_mode(aconnector, new_mode)) {
+ drm_mode_probed_add(&aconnector->base, new_mode);
+ new_modes_count += 1;
+ } else
+ drm_mode_destroy(aconnector->base.dev, new_mode);
+ }
+ out:
+ return new_modes_count;
+ }
+
+ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
+ struct edid *edid)
+ {
+ struct amdgpu_dm_connector *amdgpu_dm_connector =
+ to_amdgpu_dm_connector(connector);
+
+ if (!(amdgpu_freesync_vid_mode && edid))
+ return;
+
+ if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+ amdgpu_dm_connector->num_modes +=
+ add_fs_modes(amdgpu_dm_connector);
+ }
+
static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
{
struct amdgpu_dm_connector *amdgpu_dm_connector =
} else {
amdgpu_dm_connector_ddc_get_modes(connector, edid);
amdgpu_dm_connector_add_common_modes(encoder, connector);
+ amdgpu_dm_connector_add_freesync_modes(connector, edid);
}
amdgpu_dm_fbc_init(connector);
adev,
&adev->pageflip_irq,
irq_type);
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ amdgpu_irq_get(
+ adev,
+ &adev->vline0_irq,
+ irq_type);
+ #endif
} else {
-
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ amdgpu_irq_put(
+ adev,
+ &adev->vline0_irq,
+ irq_type);
+ #endif
amdgpu_irq_put(
adev,
&adev->pageflip_irq,
int x, y;
int xorigin = 0, yorigin = 0;
- position->enable = false;
- position->x = 0;
- position->y = 0;
-
if (!crtc || !plane->state->fb)
return 0;
struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
uint64_t address = afb ? afb->address : 0;
- struct dc_cursor_position position;
+ struct dc_cursor_position position = {0};
struct dc_cursor_attributes attributes;
int ret;
if (!plane->state->fb && !old_plane_state->fb)
return;
- DRM_DEBUG_DRIVER("%s: crtc_id=%d with size %d to %d\n",
- __func__,
- amdgpu_crtc->crtc_id,
- plane->state->crtc_w,
- plane->state->crtc_h);
+ DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
+ __func__,
+ amdgpu_crtc->crtc_id,
+ plane->state->crtc_w,
+ plane->state->crtc_h);
ret = get_cursor_position(plane, crtc, &position);
if (ret)
/* Mark this event as consumed */
acrtc->base.state->event = NULL;
- DRM_DEBUG_DRIVER("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
- acrtc->crtc_id);
+ DC_LOG_PFLIP("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+ acrtc->crtc_id);
}
static void update_freesync_state_on_stream(
struct amdgpu_device *adev = dm->adev;
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
unsigned long flags;
+ bool pack_sdp_v1_3 = false;
if (!new_stream)
return;
&vrr_params,
PACKET_TYPE_VRR,
TRANSFER_FUNC_UNKNOWN,
- &vrr_infopacket);
+ &vrr_infopacket,
+ pack_sdp_v1_3);
new_crtc_state->freesync_timing_changed |=
(memcmp(&acrtc->dm_irq_params.vrr_params.adjust,
if (new_crtc_state->vrr_supported &&
config.min_refresh_in_uhz &&
config.max_refresh_in_uhz) {
- config.state = new_crtc_state->base.vrr_enabled ?
- VRR_STATE_ACTIVE_VARIABLE :
- VRR_STATE_INACTIVE;
+ /*
+ * if freesync compatible mode was set, config.state will be set
+ * in atomic check
+ */
+ if (config.state == VRR_STATE_ACTIVE_FIXED && config.fixed_refresh_in_uhz &&
+ (!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) ||
+ new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)) {
+ vrr_params.max_refresh_in_uhz = config.max_refresh_in_uhz;
+ vrr_params.min_refresh_in_uhz = config.min_refresh_in_uhz;
+ vrr_params.fixed_refresh_in_uhz = config.fixed_refresh_in_uhz;
+ vrr_params.state = VRR_STATE_ACTIVE_FIXED;
+ } else {
+ config.state = new_crtc_state->base.vrr_enabled ?
+ VRR_STATE_ACTIVE_VARIABLE :
+ VRR_STATE_INACTIVE;
+ }
} else {
config.state = VRR_STATE_UNSUPPORTED;
}
&bundle->flip_addrs[planes_count].address,
afb->tmz_surface, false);
- DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n",
+ DRM_DEBUG_ATOMIC("plane: id=%d dcc_en=%d\n",
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
dc_plane,
bundle->flip_addrs[planes_count].flip_timestamp_in_us);
- DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n",
+ DRM_DEBUG_ATOMIC("%s Flipping to hi: 0x%x, low: 0x%x\n",
__func__,
bundle->flip_addrs[planes_count].address.grph.addr.high_part,
bundle->flip_addrs[planes_count].address.grph.addr.low_part);
* re-adjust the min/max bounds now that DC doesn't handle this
* as part of commit.
*/
- if (amdgpu_dm_vrr_active(dm_old_crtc_state) !=
- amdgpu_dm_vrr_active(acrtc_state)) {
+ if (is_dc_timing_adjust_needed(dm_old_crtc_state, acrtc_state)) {
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
dc_stream_adjust_vmin_vmax(
dm->dc, acrtc_state->stream,
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- DRM_DEBUG_DRIVER(
+ DRM_DEBUG_ATOMIC(
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
if (modeset_required(new_crtc_state, dm_new_crtc_state->stream, dm_old_crtc_state->stream)) {
- DRM_DEBUG_DRIVER("Atomic commit: SET crtc id %d: [%p]\n", acrtc->crtc_id, acrtc);
+ DRM_DEBUG_ATOMIC("Atomic commit: SET crtc id %d: [%p]\n", acrtc->crtc_id, acrtc);
if (!dm_new_crtc_state->stream) {
/*
crtc->hwmode = new_crtc_state->mode;
mode_set_reset_required = true;
} else if (modereset_required(new_crtc_state)) {
- DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
+ DRM_DEBUG_ATOMIC("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
/* i.e. reset mode */
if (dm_old_crtc_state->stream)
remove_stream(adev, acrtc, dm_old_crtc_state->stream);
+
mode_set_reset_required = true;
}
} /* for_each_crtc_in_state() */
dm_enable_per_frame_crtc_master_sync(dc_state);
mutex_lock(&dm->dc_lock);
WARN_ON(!dc_commit_state(dm->dc, dc_state));
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* Allow idle optimization when vblank count is 0 for display off */
+ if (dm->active_vblank_irq_count == 0)
+ dc_allow_idle_optimizations(dm->dc,true);
+ #endif
mutex_unlock(&dm->dc_lock);
}
hdcp_update_display(
adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
new_con_state->hdcp_content_type,
- new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED ? true
- : false);
+ new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED);
}
#endif
*/
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
-
+ #ifdef CONFIG_DEBUG_FS
+ bool configure_crc = false;
+ enum amdgpu_dm_pipe_crc_source cur_crc_src;
+ #endif
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
if (new_crtc_state->active &&
* settings for the stream.
*/
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+ cur_crc_src = acrtc->dm_irq_params.crc_src;
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
+
+ if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) {
+ configure_crc = true;
+ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ if (amdgpu_dm_crc_window_is_activated(crtc))
+ configure_crc = false;
+ #endif
+ }
- if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
+ if (configure_crc)
amdgpu_dm_crtc_configure_crc_source(
- crtc, dm_new_crtc_state,
- dm_new_crtc_state->crc_src);
- }
+ crtc, dm_new_crtc_state, cur_crc_src);
#endif
}
}
to_amdgpu_dm_connector(new_con_state->base.connector);
struct drm_display_mode *mode = &new_crtc_state->base.mode;
int vrefresh = drm_mode_vrefresh(mode);
+ bool fs_vid_mode = false;
new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
vrefresh >= aconnector->min_vfreq &&
if (new_crtc_state->vrr_supported) {
new_crtc_state->stream->ignore_msa_timing_param = true;
- config.state = new_crtc_state->base.vrr_enabled ?
- VRR_STATE_ACTIVE_VARIABLE :
- VRR_STATE_INACTIVE;
- config.min_refresh_in_uhz =
- aconnector->min_vfreq * 1000000;
- config.max_refresh_in_uhz =
- aconnector->max_vfreq * 1000000;
+ fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
+
+ config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000;
+ config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000;
config.vsif_supported = true;
config.btr = true;
- }
+ if (fs_vid_mode) {
+ config.state = VRR_STATE_ACTIVE_FIXED;
+ config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz;
+ goto out;
+ } else if (new_crtc_state->base.vrr_enabled) {
+ config.state = VRR_STATE_ACTIVE_VARIABLE;
+ } else {
+ config.state = VRR_STATE_INACTIVE;
+ }
+ }
+ out:
new_crtc_state->freesync_config = config;
}
sizeof(new_crtc_state->vrr_infopacket));
}
+ static bool
+ is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
+ struct drm_crtc_state *new_crtc_state)
+ {
+ struct drm_display_mode old_mode, new_mode;
+
+ if (!old_crtc_state || !new_crtc_state)
+ return false;
+
+ old_mode = old_crtc_state->mode;
+ new_mode = new_crtc_state->mode;
+
+ if (old_mode.clock == new_mode.clock &&
+ old_mode.hdisplay == new_mode.hdisplay &&
+ old_mode.vdisplay == new_mode.vdisplay &&
+ old_mode.htotal == new_mode.htotal &&
+ old_mode.vtotal != new_mode.vtotal &&
+ old_mode.hsync_start == new_mode.hsync_start &&
+ old_mode.vsync_start != new_mode.vsync_start &&
+ old_mode.hsync_end == new_mode.hsync_end &&
+ old_mode.vsync_end != new_mode.vsync_end &&
+ old_mode.hskew == new_mode.hskew &&
+ old_mode.vscan == new_mode.vscan &&
+ (old_mode.vsync_end - old_mode.vsync_start) ==
+ (new_mode.vsync_end - new_mode.vsync_start))
+ return true;
+
+ return false;
+ }
+
+ static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) {
+ uint64_t num, den, res;
+ struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
+
+ dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
+
+ num = (unsigned long long)new_crtc_state->mode.clock * 1000 * 1000000;
+ den = (unsigned long long)new_crtc_state->mode.htotal *
+ (unsigned long long)new_crtc_state->mode.vtotal;
+
+ res = div_u64(num, den);
+ dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res;
+ }
+
static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
struct drm_atomic_state *state,
struct drm_crtc *crtc,
* TODO: Refactor this function to allow this check to work
* in all conditions.
*/
+ if (amdgpu_freesync_vid_mode &&
+ dm_new_crtc_state->stream &&
+ is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
+ goto skip_modeset;
+
if (dm_new_crtc_state->stream &&
dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
goto skip_modeset;
- DRM_DEBUG_DRIVER(
+ DRM_DEBUG_ATOMIC(
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
if (!dm_old_crtc_state->stream)
goto skip_modeset;
+ if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
+ is_timing_unchanged_for_freesync(new_crtc_state,
+ old_crtc_state)) {
+ new_crtc_state->mode_changed = false;
+ DRM_DEBUG_DRIVER(
+ "Mode change not required for front porch change, "
+ "setting mode_changed to %d",
+ new_crtc_state->mode_changed);
+
+ set_freesync_fixed_config(dm_new_crtc_state);
+
+ goto skip_modeset;
+ } else if (amdgpu_freesync_vid_mode && aconnector &&
+ is_freesync_video_mode(&new_crtc_state->mode,
+ aconnector)) {
+ set_freesync_fixed_config(dm_new_crtc_state);
+ }
+
ret = dm_atomic_get_state(state, &dm_state);
if (ret)
goto fail;
dc_stream_retain(new_stream);
- DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n",
+ crtc->base.id);
if (dc_add_stream_to_ctx(
dm->dc,
if (!dc_new_plane_state)
return -ENOMEM;
- DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
- plane->base.id, new_plane_crtc->base.id);
+ DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n",
+ plane->base.id, new_plane_crtc->base.id);
ret = fill_dc_plane_attributes(
drm_to_adev(new_plane_crtc->dev),
new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor);
new_primary_state = drm_atomic_get_new_plane_state(state, crtc->primary);
- if (!new_cursor_state || !new_primary_state || !new_cursor_state->fb) {
+ if (!new_cursor_state || !new_primary_state ||
+ !new_cursor_state->fb || !new_primary_state->fb) {
return 0;
}
}
#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (adev->asic_type >= CHIP_NAVI10) {
+ if (dc_resource_is_dsc_encoding_supported(dc)) {
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = add_affected_mst_dsc_crtcs(state, crtc);
return capable;
}
+
+ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
+ uint8_t *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+ int i;
+ struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+ struct dc *dc = adev->dm.dc;
+
+ /* send extension block to DMCU for parsing */
+ for (i = 0; i < len; i += 8) {
+ bool res;
+ int offset;
+
+ /* send 8 bytes a time */
+ if (!dc_edid_parser_send_cea(dc, i, len, &edid_ext[i], 8))
+ return false;
+
+ if (i+8 == len) {
+ /* EDID block sent completed, expect result */
+ int version, min_rate, max_rate;
+
+ res = dc_edid_parser_recv_amd_vsdb(dc, &version, &min_rate, &max_rate);
+ if (res) {
+ /* amd vsdb found */
+ vsdb_info->freesync_supported = 1;
+ vsdb_info->amd_vsdb_version = version;
+ vsdb_info->min_refresh_rate_hz = min_rate;
+ vsdb_info->max_refresh_rate_hz = max_rate;
+ return true;
+ }
+ /* not amd vsdb */
+ return false;
+ }
+
+ /* check for ack*/
+ res = dc_edid_parser_recv_cea_ack(dc, &offset);
+ if (!res)
+ return false;
+ }
+
+ return false;
+ }
+
+ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+ struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+ uint8_t *edid_ext = NULL;
+ int i;
+ bool valid_vsdb_found = false;
+
+ /*----- drm_find_cea_extension() -----*/
+ /* No EDID or EDID extensions */
+ if (edid == NULL || edid->extensions == 0)
+ return -ENODEV;
+
+ /* Find CEA extension */
+ for (i = 0; i < edid->extensions; i++) {
+ edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1);
+ if (edid_ext[0] == CEA_EXT)
+ break;
+ }
+
+ if (i == edid->extensions)
+ return -ENODEV;
+
+ /*----- cea_db_offsets() -----*/
+ if (edid_ext[0] != CEA_EXT)
+ return -ENODEV;
+
+ valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
+
+ return valid_vsdb_found ? i : -ENODEV;
+ }
+
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
struct edid *edid)
{
- int i;
- bool edid_check_required;
+ int i = 0;
struct detailed_timing *timing;
struct detailed_non_pixel *data;
struct detailed_data_monitor_range *range;
struct drm_device *dev = connector->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
bool freesync_capable = false;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
if (!connector->state) {
DRM_ERROR("%s - Connector has no state", __func__);
dm_con_state = to_dm_connector_state(connector->state);
- edid_check_required = false;
if (!amdgpu_dm_connector->dc_sink) {
DRM_ERROR("dc_sink NULL, could not add free_sync module.\n");
goto update;
}
if (!adev->dm.freesync_module)
goto update;
- /*
- * if edid non zero restrict freesync only for dp and edp
- */
- if (edid) {
- if (amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT
- || amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_EDP) {
+
+
+ if (amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT
+ || amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_EDP) {
+ bool edid_check_required = false;
+
+ if (edid) {
edid_check_required = is_dp_capable_without_timing_msa(
adev->dm.dc,
amdgpu_dm_connector);
}
- }
- if (edid_check_required == true && (edid->version > 1 ||
- (edid->version == 1 && edid->revision > 1))) {
- for (i = 0; i < 4; i++) {
- timing = &edid->detailed_timings[i];
- data = &timing->data.other_data;
- range = &data->data.range;
- /*
- * Check if monitor has continuous frequency mode
- */
- if (data->type != EDID_DETAIL_MONITOR_RANGE)
- continue;
- /*
- * Check for flag range limits only. If flag == 1 then
- * no additional timing information provided.
- * Default GTF, GTF Secondary curve and CVT are not
- * supported
- */
- if (range->flags != 1)
- continue;
+ if (edid_check_required == true && (edid->version > 1 ||
+ (edid->version == 1 && edid->revision > 1))) {
+ for (i = 0; i < 4; i++) {
- amdgpu_dm_connector->min_vfreq = range->min_vfreq;
- amdgpu_dm_connector->max_vfreq = range->max_vfreq;
- amdgpu_dm_connector->pixel_clock_mhz =
- range->pixel_clock_mhz * 10;
+ timing = &edid->detailed_timings[i];
+ data = &timing->data.other_data;
+ range = &data->data.range;
+ /*
+ * Check if monitor has continuous frequency mode
+ */
+ if (data->type != EDID_DETAIL_MONITOR_RANGE)
+ continue;
+ /*
+ * Check for flag range limits only. If flag == 1 then
+ * no additional timing information provided.
+ * Default GTF, GTF Secondary curve and CVT are not
+ * supported
+ */
+ if (range->flags != 1)
+ continue;
- connector->display_info.monitor_range.min_vfreq = range->min_vfreq;
- connector->display_info.monitor_range.max_vfreq = range->max_vfreq;
+ amdgpu_dm_connector->min_vfreq = range->min_vfreq;
+ amdgpu_dm_connector->max_vfreq = range->max_vfreq;
+ amdgpu_dm_connector->pixel_clock_mhz =
+ range->pixel_clock_mhz * 10;
- break;
- }
+ connector->display_info.monitor_range.min_vfreq = range->min_vfreq;
+ connector->display_info.monitor_range.max_vfreq = range->max_vfreq;
- if (amdgpu_dm_connector->max_vfreq -
- amdgpu_dm_connector->min_vfreq > 10) {
+ break;
+ }
+
+ if (amdgpu_dm_connector->max_vfreq -
+ amdgpu_dm_connector->min_vfreq > 10) {
- freesync_capable = true;
+ freesync_capable = true;
+ }
+ }
+ } else if (edid && amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+ i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
+ if (i >= 0 && vsdb_info.freesync_supported) {
+ timing = &edid->detailed_timings[i];
+ data = &timing->data.other_data;
+
+ amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
+ amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
+ if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+ freesync_capable = true;
+
+ connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
+ connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
}
* Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
* positive if @lh_b is better than @lh_a.
*/
-static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
+static int drm_mode_compare(void *priv, const struct list_head *lh_a,
+ const struct list_head *lh_b)
{
struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
{
struct drm_display_mode *mode;
+ if (cmd->xres == 0 || cmd->yres == 0)
+ return NULL;
+
if (cmd->cvt)
mode = drm_cvt_mode(dev,
cmd->xres, cmd->yres,
#include "intel_dp_link_training.h"
static void
- intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
+ intel_dp_dump_link_status(struct drm_device *drm,
+ const u8 link_status[DP_LINK_STATUS_SIZE])
{
-
- DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
- link_status[0], link_status[1], link_status[2],
- link_status[3], link_status[4], link_status[5]);
+ drm_dbg_kms(drm,
+ "ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n",
+ link_status[0], link_status[1], link_status[2],
+ link_status[3], link_status[4], link_status[5]);
}
static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp)
* Detecting LTTPRs must be avoided on platforms with an AUX timeout
* period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1).
*/
- if (INTEL_GEN(i915) < 10)
+ if (DISPLAY_VER(i915) < 10)
return false;
if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
}
+ static char dp_training_pattern_name(u8 train_pat)
+ {
+ switch (train_pat) {
+ case DP_TRAINING_PATTERN_1:
+ case DP_TRAINING_PATTERN_2:
+ case DP_TRAINING_PATTERN_3:
+ return '0' + train_pat;
+ case DP_TRAINING_PATTERN_4:
+ return '4';
+ default:
+ MISSING_CASE(train_pat);
+ return '?';
+ }
+ }
+
+ void
+ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state,
+ u8 dp_train_pat)
+ {
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ u8 train_pat = intel_dp_training_pattern_symbol(dp_train_pat);
+
+ if (train_pat != DP_TRAINING_PATTERN_DISABLE)
+ drm_dbg_kms(&dev_priv->drm,
+ "[ENCODER:%d:%s] Using DP training pattern TPS%c\n",
+ encoder->base.base.id, encoder->base.name,
+ dp_training_pattern_name(train_pat));
+
+ intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat);
+ }
+
void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
enum drm_dp_phy dp_phy)
/* Make sure clock is still ok */
if (!drm_dp_clock_recovery_ok(link_status,
crtc_state->lane_count)) {
- intel_dp_dump_link_status(link_status);
+ intel_dp_dump_link_status(&i915->drm, link_status);
drm_dbg_kms(&i915->drm,
"Clock recovery check failed, cannot "
"continue channel equalization\n");
/* Try 5 times, else fail and try at lower BW */
if (tries == 5) {
- intel_dp_dump_link_status(link_status);
+ intel_dp_dump_link_status(&i915->drm, link_status);
drm_dbg_kms(&i915->drm,
"Channel equalization failed 5 times\n");
}
out:
drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
- "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s",
+ "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s\n",
intel_connector->base.base.id,
intel_connector->base.name,
ret ? "passed" : "failed",
int lttpr_count = intel_dp_init_lttpr_and_dprx_caps(intel_dp);
if (lttpr_count < 0)
- return;
+ /* Still continue with enabling the port and link training. */
+ lttpr_count = 0;
if (!intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count))
intel_dp_schedule_fallback_link_training(intel_dp, crtc_state);
#include "intel_fifo_underrun.h"
#include "intel_panel.h"
#include "intel_sideband.h"
+ #include "skl_scaler.h"
/* return pixels in terms of txbyteclkhs */
static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
* FIXME As we do with eDP, just make a note of the time here
* and perform the wait before the next panel power on.
*/
- intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+ msleep(intel_dsi->panel_pwr_cycle_delay);
}
static void intel_dsi_shutdown(struct intel_encoder *encoder)
{
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+ msleep(intel_dsi->panel_pwr_cycle_delay);
}
static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
+ // SPDX-License-Identifier: MIT
/*
- * SPDX-License-Identifier: MIT
- *
* Copyright © 2019 Intel Corporation
*/
[VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE,
};
-static int engine_cmp(void *priv, struct list_head *A, struct list_head *B)
+static int engine_cmp(void *priv, const struct list_head *A,
+ const struct list_head *B)
{
const struct intel_engine_cs *a =
container_of((struct rb_node *)A, typeof(*a), uabi_node);
#include "display/intel_display_types.h"
#include "display/intel_fbc.h"
#include "display/intel_sprite.h"
+ #include "display/skl_universal_plane.h"
#include "gt/intel_llc.h"
if (IS_I945GM(dev_priv))
wm_info = &i945_wm_info;
- else if (!IS_GEN(dev_priv, 2))
+ else if (!IS_DISPLAY_VER(dev_priv, 2))
wm_info = &i915_wm_info;
else
wm_info = &i830_a_wm_info;
crtc->base.primary->state->fb;
int cpp;
- if (IS_GEN(dev_priv, 2))
+ if (IS_DISPLAY_VER(dev_priv, 2))
cpp = 4;
else
cpp = fb->format->cpp[0];
planea_wm = wm_info->max_wm;
}
- if (IS_GEN(dev_priv, 2))
+ if (IS_DISPLAY_VER(dev_priv, 2))
wm_info = &i830_bc_wm_info;
fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B);
crtc->base.primary->state->fb;
int cpp;
- if (IS_GEN(dev_priv, 2))
+ if (IS_DISPLAY_VER(dev_priv, 2))
cpp = 4;
else
cpp = fb->format->cpp[0];
static unsigned int
ilk_display_fifo_size(const struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 8)
+ if (DISPLAY_VER(dev_priv) >= 8)
return 3072;
- else if (INTEL_GEN(dev_priv) >= 7)
+ else if (DISPLAY_VER(dev_priv) >= 7)
return 768;
else
return 512;
ilk_plane_wm_reg_max(const struct drm_i915_private *dev_priv,
int level, bool is_sprite)
{
- if (INTEL_GEN(dev_priv) >= 8)
+ if (DISPLAY_VER(dev_priv) >= 8)
/* BDW primary/sprite plane watermarks */
return level == 0 ? 255 : 2047;
- else if (INTEL_GEN(dev_priv) >= 7)
+ else if (DISPLAY_VER(dev_priv) >= 7)
/* IVB/HSW primary/sprite plane watermarks */
return level == 0 ? 127 : 1023;
else if (!is_sprite)
static unsigned int
ilk_cursor_wm_reg_max(const struct drm_i915_private *dev_priv, int level)
{
- if (INTEL_GEN(dev_priv) >= 7)
+ if (DISPLAY_VER(dev_priv) >= 7)
return level == 0 ? 63 : 255;
else
return level == 0 ? 31 : 63;
static unsigned int ilk_fbc_wm_reg_max(const struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 8)
+ if (DISPLAY_VER(dev_priv) >= 8)
return 31;
else
return 15;
* FIFO size is only half of the self
* refresh FIFO size on ILK/SNB.
*/
- if (INTEL_GEN(dev_priv) <= 6)
+ if (DISPLAY_VER(dev_priv) <= 6)
fifo_size /= 2;
}
{
struct intel_uncore *uncore = &dev_priv->uncore;
- if (INTEL_GEN(dev_priv) >= 9) {
+ if (DISPLAY_VER(dev_priv) >= 9) {
u32 val;
int ret, i;
int level, max_level = ilk_wm_max_level(dev_priv);
wm[2] = (sskpd >> 12) & 0xFF;
wm[3] = (sskpd >> 20) & 0x1FF;
wm[4] = (sskpd >> 32) & 0x1FF;
- } else if (INTEL_GEN(dev_priv) >= 6) {
+ } else if (DISPLAY_VER(dev_priv) >= 6) {
u32 sskpd = intel_uncore_read(uncore, MCH_SSKPD);
wm[0] = (sskpd >> SSKPD_WM0_SHIFT) & SSKPD_WM_MASK;
wm[1] = (sskpd >> SSKPD_WM1_SHIFT) & SSKPD_WM_MASK;
wm[2] = (sskpd >> SSKPD_WM2_SHIFT) & SSKPD_WM_MASK;
wm[3] = (sskpd >> SSKPD_WM3_SHIFT) & SSKPD_WM_MASK;
- } else if (INTEL_GEN(dev_priv) >= 5) {
+ } else if (DISPLAY_VER(dev_priv) >= 5) {
u32 mltr = intel_uncore_read(uncore, MLTR_ILK);
/* ILK primary LP0 latency is 700 ns */
u16 wm[5])
{
/* ILK sprite LP0 latency is 1300 ns */
- if (IS_GEN(dev_priv, 5))
+ if (IS_DISPLAY_VER(dev_priv, 5))
wm[0] = 13;
}
u16 wm[5])
{
/* ILK cursor LP0 latency is 1300 ns */
- if (IS_GEN(dev_priv, 5))
+ if (IS_DISPLAY_VER(dev_priv, 5))
wm[0] = 13;
}
int ilk_wm_max_level(const struct drm_i915_private *dev_priv)
{
/* how many WM levels are we expecting */
- if (INTEL_GEN(dev_priv) >= 9)
+ if (DISPLAY_VER(dev_priv) >= 9)
return 7;
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
return 4;
- else if (INTEL_GEN(dev_priv) >= 6)
+ else if (DISPLAY_VER(dev_priv) >= 6)
return 3;
else
return 2;
static void intel_print_wm_latency(struct drm_i915_private *dev_priv,
const char *name,
- const u16 wm[8])
+ const u16 wm[])
{
int level, max_level = ilk_wm_max_level(dev_priv);
* - latencies are in us on gen9.
* - before then, WM1+ latency values are in 0.5us units
*/
- if (INTEL_GEN(dev_priv) >= 9)
+ if (DISPLAY_VER(dev_priv) >= 9)
latency *= 10;
else if (level > 0)
latency *= 5;
intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
- if (IS_GEN(dev_priv, 6)) {
+ if (IS_DISPLAY_VER(dev_priv, 6)) {
snb_wm_latency_quirk(dev_priv);
snb_wm_lp3_irq_quirk(dev_priv);
}
usable_level = max_level;
/* ILK/SNB: LP2+ watermarks only w/o sprites */
- if (INTEL_GEN(dev_priv) <= 6 && pipe_wm->sprites_enabled)
+ if (DISPLAY_VER(dev_priv) <= 6 && pipe_wm->sprites_enabled)
usable_level = 1;
/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
int last_enabled_level = max_level;
/* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
- if ((INTEL_GEN(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) &&
+ if ((DISPLAY_VER(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) &&
config->num_pipes_active > 1)
last_enabled_level = 0;
/* ILK: FBC WM must be disabled always */
- merged->fbc_wm_enabled = INTEL_GEN(dev_priv) >= 6;
+ merged->fbc_wm_enabled = DISPLAY_VER(dev_priv) >= 6;
/* merge each WM1+ level */
for (level = 1; level <= max_level; level++) {
* What we should check here is whether FBC can be
* enabled sometime later.
*/
- if (IS_GEN(dev_priv, 5) && !merged->fbc_wm_enabled &&
+ if (IS_DISPLAY_VER(dev_priv, 5) && !merged->fbc_wm_enabled &&
intel_fbc_is_active(dev_priv)) {
for (level = 2; level <= max_level; level++) {
struct intel_wm_level *wm = &merged->wm[level];
if (r->enable)
results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
- if (INTEL_GEN(dev_priv) >= 8)
+ if (DISPLAY_VER(dev_priv) >= 8)
results->wm_lp[wm_lp - 1] |=
r->fbc_val << WM1_LP_FBC_SHIFT_BDW;
else
* Always set WM1S_LP_EN when spr_val != 0, even if the
* level is disabled. Doing otherwise could cause underruns.
*/
- if (INTEL_GEN(dev_priv) <= 6 && r->spr_val) {
+ if (DISPLAY_VER(dev_priv) <= 6 && r->spr_val) {
drm_WARN_ON(&dev_priv->drm, wm_lp != 1);
results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val;
} else
previous->wm_lp_spr[0] != results->wm_lp_spr[0])
intel_uncore_write(&dev_priv->uncore, WM1S_LP_ILK, results->wm_lp_spr[0]);
- if (INTEL_GEN(dev_priv) >= 7) {
+ if (DISPLAY_VER(dev_priv) >= 7) {
if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
intel_uncore_write(&dev_priv->uncore, WM2S_LP_IVB, results->wm_lp_spr[1]);
if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
static bool
intel_has_sagv(struct drm_i915_private *dev_priv)
{
- return (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) &&
+ return (IS_GEN9_BC(dev_priv) || DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) &&
dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED;
}
static void
skl_setup_sagv_block_time(struct drm_i915_private *dev_priv)
{
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (DISPLAY_VER(dev_priv) >= 12) {
u32 val = 0;
int ret;
}
drm_dbg(&dev_priv->drm, "Couldn't read SAGV block time!\n");
- } else if (IS_GEN(dev_priv, 11)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 11)) {
dev_priv->sagv_block_time_us = 10;
return;
- } else if (IS_GEN(dev_priv, 10)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 10)) {
dev_priv->sagv_block_time_us = 20;
return;
- } else if (IS_GEN(dev_priv, 9)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 9)) {
dev_priv->sagv_block_time_us = 30;
return;
} else {
- MISSING_CASE(INTEL_GEN(dev_priv));
+ MISSING_CASE(DISPLAY_VER(dev_priv));
}
/* Default to an unusable block time */
if (!new_bw_state)
return;
- if (INTEL_GEN(dev_priv) < 11 && !intel_can_enable_sagv(dev_priv, new_bw_state)) {
+ if (DISPLAY_VER(dev_priv) < 11 && !intel_can_enable_sagv(dev_priv, new_bw_state)) {
intel_disable_sagv(dev_priv);
return;
}
if (!new_bw_state)
return;
- if (INTEL_GEN(dev_priv) < 11 && intel_can_enable_sagv(dev_priv, new_bw_state)) {
+ if (DISPLAY_VER(dev_priv) < 11 && intel_can_enable_sagv(dev_priv, new_bw_state)) {
intel_enable_sagv(dev_priv);
return;
}
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum plane_id plane_id;
+ int max_level = INT_MAX;
if (!intel_has_sagv(dev_priv))
return false;
int level;
/* Skip this plane if it's not enabled */
- if (!wm->wm[0].plane_en)
+ if (!wm->wm[0].enable)
continue;
/* Find the highest enabled wm level for this plane */
for (level = ilk_wm_max_level(dev_priv);
- !wm->wm[level].plane_en; --level)
+ !wm->wm[level].enable; --level)
{ }
+ /* Highest common enabled wm level for all planes */
+ max_level = min(level, max_level);
+ }
+
+ /* No enabled planes? */
+ if (max_level == INT_MAX)
+ return true;
+
+ for_each_plane_id_on_crtc(crtc, plane_id) {
+ const struct skl_plane_wm *wm =
+ &crtc_state->wm.skl.optimal.planes[plane_id];
+
/*
- * If any of the planes on this pipe don't enable wm levels that
- * incur memory latencies higher than sagv_block_time_us we
- * can't enable SAGV.
+ * All enabled planes must have enabled a common wm level that
+ * can tolerate memory latencies higher than sagv_block_time_us
*/
- if (!wm->wm[level].can_sagv)
+ if (wm->wm[0].enable && !wm->wm[max_level].can_sagv)
return false;
}
return true;
for_each_plane_id_on_crtc(crtc, plane_id) {
- const struct skl_ddb_entry *plane_alloc =
- &crtc_state->wm.skl.plane_ddb_y[plane_id];
const struct skl_plane_wm *wm =
&crtc_state->wm.skl.optimal.planes[plane_id];
- if (skl_ddb_entry_size(plane_alloc) < wm->sagv_wm0.min_ddb_alloc)
+ if (wm->wm[0].enable && !wm->sagv.wm0.enable)
return false;
}
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- if (INTEL_GEN(dev_priv) >= 12)
+ if (DISPLAY_VER(dev_priv) >= 12)
return tgl_crtc_can_enable_sagv(crtc_state);
else
return skl_crtc_can_enable_sagv(crtc_state);
bool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
const struct intel_bw_state *bw_state)
{
- if (INTEL_GEN(dev_priv) < 11 &&
+ if (DISPLAY_VER(dev_priv) < 11 &&
bw_state->active_pipes && !is_power_of_2(bw_state->active_pipes))
return false;
* latter from the plane commit hooks (especially in the legacy
* cursor case)
*/
- pipe_wm->use_sagv_wm = INTEL_GEN(dev_priv) >= 12 &&
+ pipe_wm->use_sagv_wm = DISPLAY_VER(dev_priv) >= 12 &&
intel_can_enable_sagv(dev_priv, new_bw_state);
}
drm_WARN_ON(&dev_priv->drm, ddb_size == 0);
- if (INTEL_GEN(dev_priv) < 11)
+ if (DISPLAY_VER(dev_priv) < 11)
return ddb_size - 4; /* 4 blocks for bypass path allocation */
return ddb_size;
val & PLANE_CTL_ORDER_RGBX,
val & PLANE_CTL_ALPHA_MASK);
- if (INTEL_GEN(dev_priv) >= 11) {
+ if (DISPLAY_VER(dev_priv) >= 11) {
val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id));
skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
} else {
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
- if (IS_GEN(dev_priv, 12))
+ if (IS_DISPLAY_VER(dev_priv, 12))
return tgl_compute_dbuf_slices(pipe, active_pipes);
- else if (IS_GEN(dev_priv, 11))
+ else if (IS_DISPLAY_VER(dev_priv, 11))
return icl_compute_dbuf_slices(pipe, active_pipes);
/*
* For anything else just return one slice yet.
return total_data_rate;
}
- static const struct skl_wm_level *
- skl_plane_wm_level(const struct intel_crtc_state *crtc_state,
+ const struct skl_wm_level *
+ skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm,
enum plane_id plane_id,
int level)
{
- const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
if (level == 0 && pipe_wm->use_sagv_wm)
- return &wm->sagv_wm0;
+ return &wm->sagv.wm0;
return &wm->wm[level];
}
+ const struct skl_wm_level *
+ skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm,
+ enum plane_id plane_id)
+ {
+ const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
+
+ if (pipe_wm->use_sagv_wm)
+ return &wm->sagv.trans_wm;
+
+ return &wm->trans_wm;
+ }
+
+ /*
+ * We only disable the watermarks for each plane if
+ * they exceed the ddb allocation of said plane. This
+ * is done so that we don't end up touching cursor
+ * watermarks needlessly when some other plane reduces
+ * our max possible watermark level.
+ *
+ * Bspec has this to say about the PLANE_WM enable bit:
+ * "All the watermarks at this level for all enabled
+ * planes must be enabled before the level will be used."
+ * So this is actually safe to do.
+ */
+ static void
+ skl_check_wm_level(struct skl_wm_level *wm, u64 total)
+ {
+ if (wm->min_ddb_alloc > total)
+ memset(wm, 0, sizeof(*wm));
+ }
+
+ static void
+ skl_check_nv12_wm_level(struct skl_wm_level *wm, struct skl_wm_level *uv_wm,
+ u64 total, u64 uv_total)
+ {
+ if (wm->min_ddb_alloc > total ||
+ uv_wm->min_ddb_alloc > uv_total) {
+ memset(wm, 0, sizeof(*wm));
+ memset(uv_wm, 0, sizeof(*uv_wm));
+ }
+ }
+
static int
skl_allocate_plane_ddb(struct intel_atomic_state *state,
struct intel_crtc *crtc)
if (!crtc_state->hw.active)
return 0;
- if (INTEL_GEN(dev_priv) >= 11)
+ if (DISPLAY_VER(dev_priv) >= 11)
total_data_rate =
icl_get_total_relative_data_rate(state, crtc);
else
/* Gen11+ uses a separate plane for UV watermarks */
drm_WARN_ON(&dev_priv->drm,
- INTEL_GEN(dev_priv) >= 11 && uv_total[plane_id]);
+ DISPLAY_VER(dev_priv) >= 11 && uv_total[plane_id]);
/* Leave disabled planes at (0,0) */
if (total[plane_id]) {
struct skl_plane_wm *wm =
&crtc_state->wm.skl.optimal.planes[plane_id];
- /*
- * We only disable the watermarks for each plane if
- * they exceed the ddb allocation of said plane. This
- * is done so that we don't end up touching cursor
- * watermarks needlessly when some other plane reduces
- * our max possible watermark level.
- *
- * Bspec has this to say about the PLANE_WM enable bit:
- * "All the watermarks at this level for all enabled
- * planes must be enabled before the level will be used."
- * So this is actually safe to do.
- */
- if (wm->wm[level].min_ddb_alloc > total[plane_id] ||
- wm->uv_wm[level].min_ddb_alloc > uv_total[plane_id])
- memset(&wm->wm[level], 0, sizeof(wm->wm[level]));
+ skl_check_nv12_wm_level(&wm->wm[level], &wm->uv_wm[level],
+ total[plane_id], uv_total[plane_id]);
/*
* Wa_1408961008:icl, ehl
* Underruns with WM1+ disabled
*/
- if (IS_GEN(dev_priv, 11) &&
- level == 1 && wm->wm[0].plane_en) {
- wm->wm[level].plane_res_b = wm->wm[0].plane_res_b;
- wm->wm[level].plane_res_l = wm->wm[0].plane_res_l;
+ if (IS_DISPLAY_VER(dev_priv, 11) &&
+ level == 1 && wm->wm[0].enable) {
+ wm->wm[level].blocks = wm->wm[0].blocks;
+ wm->wm[level].lines = wm->wm[0].lines;
wm->wm[level].ignore_lines = wm->wm[0].ignore_lines;
}
}
}
/*
- * Go back and disable the transition watermark if it turns out we
- * don't have enough DDB blocks for it.
+ * Go back and disable the transition and SAGV watermarks
+ * if it turns out we don't have enough DDB blocks for them.
*/
for_each_plane_id_on_crtc(crtc, plane_id) {
struct skl_plane_wm *wm =
&crtc_state->wm.skl.optimal.planes[plane_id];
- if (wm->trans_wm.plane_res_b >= total[plane_id])
- memset(&wm->trans_wm, 0, sizeof(wm->trans_wm));
+ skl_check_wm_level(&wm->trans_wm, total[plane_id]);
+ skl_check_wm_level(&wm->sagv.wm0, total[plane_id]);
+ skl_check_wm_level(&wm->sagv.trans_wm, total[plane_id]);
}
return 0;
wm_intermediate_val = latency * pixel_rate * cpp;
ret = div_fixed16(wm_intermediate_val, 1000 * dbuf_block_size);
- if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+ if (DISPLAY_VER(dev_priv) >= 10)
ret = add_fixed16_u32(ret, 1);
return ret;
wp->cpp = format->cpp[color_plane];
wp->plane_pixel_rate = plane_pixel_rate;
- if (INTEL_GEN(dev_priv) >= 11 &&
+ if (DISPLAY_VER(dev_priv) >= 11 &&
modifier == I915_FORMAT_MOD_Yf_TILED && wp->cpp == 1)
wp->dbuf_block_size = 256;
else
wp->y_min_scanlines,
wp->dbuf_block_size);
- if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+ if (DISPLAY_VER(dev_priv) >= 10)
interm_pbpl++;
wp->plane_blocks_per_line = div_fixed16(interm_pbpl,
interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line,
wp->dbuf_block_size);
- if (!wp->x_tiled ||
- INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+ if (!wp->x_tiled || DISPLAY_VER(dev_priv) >= 10)
interm_pbpl++;
wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
static bool skl_wm_has_lines(struct drm_i915_private *dev_priv, int level)
{
- if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+ if (DISPLAY_VER(dev_priv) >= 10)
return true;
/* The number of lines are ignored for the level 0 watermark. */
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
uint_fixed_16_16_t method1, method2;
uint_fixed_16_16_t selected_result;
- u32 res_blocks, res_lines, min_ddb_alloc = 0;
+ u32 blocks, lines, min_ddb_alloc = 0;
if (latency == 0) {
/* reject it */
(wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) {
selected_result = method2;
} else if (latency >= wp->linetime_us) {
- if (IS_GEN(dev_priv, 9) &&
- !IS_GEMINILAKE(dev_priv))
+ if (IS_DISPLAY_VER(dev_priv, 9))
selected_result = min_fixed16(method1, method2);
else
selected_result = method2;
}
}
- res_blocks = fixed16_to_u32_round_up(selected_result) + 1;
- res_lines = div_round_up_fixed16(selected_result,
- wp->plane_blocks_per_line);
+ blocks = fixed16_to_u32_round_up(selected_result) + 1;
+ lines = div_round_up_fixed16(selected_result,
+ wp->plane_blocks_per_line);
if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) {
/* Display WA #1125: skl,bxt,kbl */
if (level == 0 && wp->rc_surface)
- res_blocks +=
- fixed16_to_u32_round_up(wp->y_tile_minimum);
+ blocks += fixed16_to_u32_round_up(wp->y_tile_minimum);
/* Display WA #1126: skl,bxt,kbl */
if (level >= 1 && level <= 7) {
if (wp->y_tiled) {
- res_blocks +=
- fixed16_to_u32_round_up(wp->y_tile_minimum);
- res_lines += wp->y_min_scanlines;
+ blocks += fixed16_to_u32_round_up(wp->y_tile_minimum);
+ lines += wp->y_min_scanlines;
} else {
- res_blocks++;
+ blocks++;
}
/*
* Assumption in DDB algorithm optimization for special
* cases. Also covers Display WA #1125 for RC.
*/
- if (result_prev->plane_res_b > res_blocks)
- res_blocks = result_prev->plane_res_b;
+ if (result_prev->blocks > blocks)
+ blocks = result_prev->blocks;
}
}
- if (INTEL_GEN(dev_priv) >= 11) {
+ if (DISPLAY_VER(dev_priv) >= 11) {
if (wp->y_tiled) {
int extra_lines;
- if (res_lines % wp->y_min_scanlines == 0)
+ if (lines % wp->y_min_scanlines == 0)
extra_lines = wp->y_min_scanlines;
else
extra_lines = wp->y_min_scanlines * 2 -
- res_lines % wp->y_min_scanlines;
+ lines % wp->y_min_scanlines;
- min_ddb_alloc = mul_round_up_u32_fixed16(res_lines + extra_lines,
+ min_ddb_alloc = mul_round_up_u32_fixed16(lines + extra_lines,
wp->plane_blocks_per_line);
} else {
- min_ddb_alloc = res_blocks +
- DIV_ROUND_UP(res_blocks, 10);
+ min_ddb_alloc = blocks + DIV_ROUND_UP(blocks, 10);
}
}
if (!skl_wm_has_lines(dev_priv, level))
- res_lines = 0;
+ lines = 0;
- if (res_lines > 31) {
+ if (lines > 31) {
/* reject it */
result->min_ddb_alloc = U16_MAX;
return;
}
/*
- * If res_lines is valid, assume we can use this watermark level
+ * If lines is valid, assume we can use this watermark level
* for now. We'll come back and disable it after we calculate the
* DDB allocation if it turns out we don't actually have enough
* blocks to satisfy it.
*/
- result->plane_res_b = res_blocks;
- result->plane_res_l = res_lines;
+ result->blocks = blocks;
+ result->lines = lines;
/* Bspec says: value >= plane ddb allocation -> invalid, hence the +1 here */
- result->min_ddb_alloc = max(min_ddb_alloc, res_blocks) + 1;
- result->plane_en = true;
+ result->min_ddb_alloc = max(min_ddb_alloc, blocks) + 1;
+ result->enable = true;
- if (INTEL_GEN(dev_priv) < 12)
+ if (DISPLAY_VER(dev_priv) < 12)
result->can_sagv = latency >= dev_priv->sagv_block_time_us;
}
struct skl_plane_wm *plane_wm)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
- struct skl_wm_level *sagv_wm = &plane_wm->sagv_wm0;
+ struct skl_wm_level *sagv_wm = &plane_wm->sagv.wm0;
struct skl_wm_level *levels = plane_wm->wm;
unsigned int latency = dev_priv->wm.skl_latency[0] + dev_priv->sagv_block_time_us;
sagv_wm);
}
- static void skl_compute_transition_wm(const struct intel_crtc_state *crtc_state,
- const struct skl_wm_params *wp,
- struct skl_plane_wm *wm)
+ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv,
+ struct skl_wm_level *trans_wm,
+ const struct skl_wm_level *wm0,
+ const struct skl_wm_params *wp)
{
- struct drm_device *dev = crtc_state->uapi.crtc->dev;
- const struct drm_i915_private *dev_priv = to_i915(dev);
u16 trans_min, trans_amount, trans_y_tile_min;
- u16 wm0_sel_res_b, trans_offset_b, res_blocks;
+ u16 wm0_blocks, trans_offset, blocks;
/* Transition WM don't make any sense if ipc is disabled */
if (!dev_priv->ipc_enabled)
if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv))
return;
- if (INTEL_GEN(dev_priv) >= 11)
+ if (DISPLAY_VER(dev_priv) >= 11)
trans_min = 4;
else
trans_min = 14;
/* Display WA #1140: glk,cnl */
- if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+ if (IS_DISPLAY_VER(dev_priv, 10))
trans_amount = 0;
else
trans_amount = 10; /* This is configurable amount */
- trans_offset_b = trans_min + trans_amount;
+ trans_offset = trans_min + trans_amount;
/*
* The spec asks for Selected Result Blocks for wm0 (the real value),
* not Result Blocks (the integer value). Pay attention to the capital
- * letters. The value wm_l0->plane_res_b is actually Result Blocks, but
+ * letters. The value wm_l0->blocks is actually Result Blocks, but
* since Result Blocks is the ceiling of Selected Result Blocks plus 1,
* and since we later will have to get the ceiling of the sum in the
* transition watermarks calculation, we can just pretend Selected
* Result Blocks is Result Blocks minus 1 and it should work for the
* current platforms.
*/
- wm0_sel_res_b = wm->wm[0].plane_res_b - 1;
+ wm0_blocks = wm0->blocks - 1;
if (wp->y_tiled) {
trans_y_tile_min =
(u16)mul_round_up_u32_fixed16(2, wp->y_tile_minimum);
- res_blocks = max(wm0_sel_res_b, trans_y_tile_min) +
- trans_offset_b;
+ blocks = max(wm0_blocks, trans_y_tile_min) + trans_offset;
} else {
- res_blocks = wm0_sel_res_b + trans_offset_b;
+ blocks = wm0_blocks + trans_offset;
}
+ blocks++;
/*
* Just assume we can enable the transition watermark. After
* computing the DDB we'll come back and disable it if that
* assumption turns out to be false.
*/
- wm->trans_wm.plane_res_b = res_blocks + 1;
- wm->trans_wm.plane_en = true;
+ trans_wm->blocks = blocks;
+ trans_wm->min_ddb_alloc = max_t(u16, wm0->min_ddb_alloc, blocks + 1);
+ trans_wm->enable = true;
}
static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
skl_compute_wm_levels(crtc_state, &wm_params, wm->wm);
- if (INTEL_GEN(dev_priv) >= 12)
+ skl_compute_transition_wm(dev_priv, &wm->trans_wm,
+ &wm->wm[0], &wm_params);
+
+ if (DISPLAY_VER(dev_priv) >= 12) {
tgl_compute_sagv_wm(crtc_state, &wm_params, wm);
- skl_compute_transition_wm(crtc_state, &wm_params, wm);
+ skl_compute_transition_wm(dev_priv, &wm->sagv.trans_wm,
+ &wm->sagv.wm0, &wm_params);
+ }
return 0;
}
struct skl_plane_wm *wm = &crtc_state->wm.skl.raw.planes[plane_id];
int ret;
- memset(wm, 0, sizeof(*wm));
-
/* Watermarks calculated in master */
if (plane_state->planar_slave)
return 0;
+ memset(wm, 0, sizeof(*wm));
+
if (plane_state->planar_linked_plane) {
const struct drm_framebuffer *fb = plane_state->hw.fb;
enum plane_id y_plane_id = plane_state->planar_linked_plane->id;
if (plane->pipe != crtc->pipe)
continue;
- if (INTEL_GEN(dev_priv) >= 11)
+ if (DISPLAY_VER(dev_priv) >= 11)
ret = icl_build_plane_wm(crtc_state, plane_state);
else
ret = skl_build_plane_wm(crtc_state, plane_state);
{
u32 val = 0;
- if (level->plane_en)
+ if (level->enable)
val |= PLANE_WM_EN;
if (level->ignore_lines)
val |= PLANE_WM_IGNORE_LINES;
- val |= level->plane_res_b;
- val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
+ val |= level->blocks;
+ val |= level->lines << PLANE_WM_LINES_SHIFT;
intel_de_write_fw(dev_priv, reg, val);
}
int level, max_level = ilk_wm_max_level(dev_priv);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
- const struct skl_plane_wm *wm =
- &crtc_state->wm.skl.optimal.planes[plane_id];
+ const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
+ const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
const struct skl_ddb_entry *ddb_y =
&crtc_state->wm.skl.plane_ddb_y[plane_id];
const struct skl_ddb_entry *ddb_uv =
&crtc_state->wm.skl.plane_ddb_uv[plane_id];
- for (level = 0; level <= max_level; level++) {
- const struct skl_wm_level *wm_level;
-
- wm_level = skl_plane_wm_level(crtc_state, plane_id, level);
-
+ for (level = 0; level <= max_level; level++)
skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
- wm_level);
- }
+ skl_plane_wm_level(pipe_wm, plane_id, level));
+
skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
- &wm->trans_wm);
+ skl_plane_trans_wm(pipe_wm, plane_id));
- if (INTEL_GEN(dev_priv) >= 11) {
+ if (DISPLAY_VER(dev_priv) >= 11) {
skl_ddb_entry_write(dev_priv,
PLANE_BUF_CFG(pipe, plane_id), ddb_y);
return;
int level, max_level = ilk_wm_max_level(dev_priv);
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
- const struct skl_plane_wm *wm =
- &crtc_state->wm.skl.optimal.planes[plane_id];
+ const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
const struct skl_ddb_entry *ddb =
&crtc_state->wm.skl.plane_ddb_y[plane_id];
- for (level = 0; level <= max_level; level++) {
- const struct skl_wm_level *wm_level;
-
- wm_level = skl_plane_wm_level(crtc_state, plane_id, level);
-
+ for (level = 0; level <= max_level; level++)
skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
- wm_level);
- }
- skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
+ skl_plane_wm_level(pipe_wm, plane_id, level));
+
+ skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe),
+ skl_plane_trans_wm(pipe_wm, plane_id));
skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
}
bool skl_wm_level_equals(const struct skl_wm_level *l1,
const struct skl_wm_level *l2)
{
- return l1->plane_en == l2->plane_en &&
+ return l1->enable == l2->enable &&
l1->ignore_lines == l2->ignore_lines &&
- l1->plane_res_l == l2->plane_res_l &&
- l1->plane_res_b == l2->plane_res_b;
+ l1->lines == l2->lines &&
+ l1->blocks == l2->blocks;
}
static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv,
return false;
}
- return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm);
+ return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm) &&
+ skl_wm_level_equals(&wm1->sagv.wm0, &wm2->sagv.wm0) &&
+ skl_wm_level_equals(&wm1->sagv.trans_wm, &wm2->sagv.trans_wm);
}
static bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
continue;
drm_dbg_kms(&dev_priv->drm,
- "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm"
- " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm\n",
+ "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm"
+ " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n",
plane->base.base.id, plane->base.name,
- enast(old_wm->wm[0].plane_en), enast(old_wm->wm[1].plane_en),
- enast(old_wm->wm[2].plane_en), enast(old_wm->wm[3].plane_en),
- enast(old_wm->wm[4].plane_en), enast(old_wm->wm[5].plane_en),
- enast(old_wm->wm[6].plane_en), enast(old_wm->wm[7].plane_en),
- enast(old_wm->trans_wm.plane_en),
- enast(old_wm->sagv_wm0.plane_en),
- enast(new_wm->wm[0].plane_en), enast(new_wm->wm[1].plane_en),
- enast(new_wm->wm[2].plane_en), enast(new_wm->wm[3].plane_en),
- enast(new_wm->wm[4].plane_en), enast(new_wm->wm[5].plane_en),
- enast(new_wm->wm[6].plane_en), enast(new_wm->wm[7].plane_en),
- enast(new_wm->trans_wm.plane_en),
- enast(new_wm->sagv_wm0.plane_en));
+ enast(old_wm->wm[0].enable), enast(old_wm->wm[1].enable),
+ enast(old_wm->wm[2].enable), enast(old_wm->wm[3].enable),
+ enast(old_wm->wm[4].enable), enast(old_wm->wm[5].enable),
+ enast(old_wm->wm[6].enable), enast(old_wm->wm[7].enable),
+ enast(old_wm->trans_wm.enable),
+ enast(old_wm->sagv.wm0.enable),
+ enast(old_wm->sagv.trans_wm.enable),
+ enast(new_wm->wm[0].enable), enast(new_wm->wm[1].enable),
+ enast(new_wm->wm[2].enable), enast(new_wm->wm[3].enable),
+ enast(new_wm->wm[4].enable), enast(new_wm->wm[5].enable),
+ enast(new_wm->wm[6].enable), enast(new_wm->wm[7].enable),
+ enast(new_wm->trans_wm.enable),
+ enast(new_wm->sagv.wm0.enable),
+ enast(new_wm->sagv.trans_wm.enable));
drm_dbg_kms(&dev_priv->drm,
- "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d"
- " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d\n",
+ "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d"
+ " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n",
plane->base.base.id, plane->base.name,
- enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].plane_res_l,
- enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].plane_res_l,
- enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].plane_res_l,
- enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].plane_res_l,
- enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].plane_res_l,
- enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].plane_res_l,
- enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].plane_res_l,
- enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].plane_res_l,
- enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.plane_res_l,
- enast(old_wm->sagv_wm0.ignore_lines), old_wm->sagv_wm0.plane_res_l,
-
- enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].plane_res_l,
- enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].plane_res_l,
- enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].plane_res_l,
- enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].plane_res_l,
- enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].plane_res_l,
- enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].plane_res_l,
- enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].plane_res_l,
- enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].plane_res_l,
- enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.plane_res_l,
- enast(new_wm->sagv_wm0.ignore_lines), new_wm->sagv_wm0.plane_res_l);
+ enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].lines,
+ enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].lines,
+ enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].lines,
+ enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].lines,
+ enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].lines,
+ enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].lines,
+ enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].lines,
+ enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].lines,
+ enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.lines,
+ enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.lines,
+ enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.lines,
+ enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].lines,
+ enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].lines,
+ enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].lines,
+ enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].lines,
+ enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].lines,
+ enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].lines,
+ enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].lines,
+ enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].lines,
+ enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.lines,
+ enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.lines,
+ enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.lines);
drm_dbg_kms(&dev_priv->drm,
- "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d"
- " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n",
+ "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d"
+ " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n",
plane->base.base.id, plane->base.name,
- old_wm->wm[0].plane_res_b, old_wm->wm[1].plane_res_b,
- old_wm->wm[2].plane_res_b, old_wm->wm[3].plane_res_b,
- old_wm->wm[4].plane_res_b, old_wm->wm[5].plane_res_b,
- old_wm->wm[6].plane_res_b, old_wm->wm[7].plane_res_b,
- old_wm->trans_wm.plane_res_b,
- old_wm->sagv_wm0.plane_res_b,
- new_wm->wm[0].plane_res_b, new_wm->wm[1].plane_res_b,
- new_wm->wm[2].plane_res_b, new_wm->wm[3].plane_res_b,
- new_wm->wm[4].plane_res_b, new_wm->wm[5].plane_res_b,
- new_wm->wm[6].plane_res_b, new_wm->wm[7].plane_res_b,
- new_wm->trans_wm.plane_res_b,
- new_wm->sagv_wm0.plane_res_b);
+ old_wm->wm[0].blocks, old_wm->wm[1].blocks,
+ old_wm->wm[2].blocks, old_wm->wm[3].blocks,
+ old_wm->wm[4].blocks, old_wm->wm[5].blocks,
+ old_wm->wm[6].blocks, old_wm->wm[7].blocks,
+ old_wm->trans_wm.blocks,
+ old_wm->sagv.wm0.blocks,
+ old_wm->sagv.trans_wm.blocks,
+ new_wm->wm[0].blocks, new_wm->wm[1].blocks,
+ new_wm->wm[2].blocks, new_wm->wm[3].blocks,
+ new_wm->wm[4].blocks, new_wm->wm[5].blocks,
+ new_wm->wm[6].blocks, new_wm->wm[7].blocks,
+ new_wm->trans_wm.blocks,
+ new_wm->sagv.wm0.blocks,
+ new_wm->sagv.trans_wm.blocks);
drm_dbg_kms(&dev_priv->drm,
- "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d"
- " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n",
+ "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d"
+ " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n",
plane->base.base.id, plane->base.name,
old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc,
old_wm->wm[2].min_ddb_alloc, old_wm->wm[3].min_ddb_alloc,
old_wm->wm[4].min_ddb_alloc, old_wm->wm[5].min_ddb_alloc,
old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc,
old_wm->trans_wm.min_ddb_alloc,
- old_wm->sagv_wm0.min_ddb_alloc,
+ old_wm->sagv.wm0.min_ddb_alloc,
+ old_wm->sagv.trans_wm.min_ddb_alloc,
new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc,
new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc,
new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc,
new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc,
new_wm->trans_wm.min_ddb_alloc,
- new_wm->sagv_wm0.min_ddb_alloc);
+ new_wm->sagv.wm0.min_ddb_alloc,
+ new_wm->sagv.trans_wm.min_ddb_alloc);
}
}
}
+ static bool skl_plane_selected_wm_equals(struct intel_plane *plane,
+ const struct skl_pipe_wm *old_pipe_wm,
+ const struct skl_pipe_wm *new_pipe_wm)
+ {
+ struct drm_i915_private *i915 = to_i915(plane->base.dev);
+ int level, max_level = ilk_wm_max_level(i915);
+
+ for (level = 0; level <= max_level; level++) {
+ /*
+ * We don't check uv_wm as the hardware doesn't actually
+ * use it. It only gets used for calculating the required
+ * ddb allocation.
+ */
+ if (!skl_wm_level_equals(skl_plane_wm_level(old_pipe_wm, plane->id, level),
+ skl_plane_wm_level(new_pipe_wm, plane->id, level)))
+ return false;
+ }
+
+ return skl_wm_level_equals(skl_plane_trans_wm(old_pipe_wm, plane->id),
+ skl_plane_trans_wm(new_pipe_wm, plane->id));
+ }
+
/*
* To make sure the cursor watermark registers are always consistent
* with our computed state the following scenario needs special
* with the software state.
*/
if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) &&
- skl_plane_wm_equals(dev_priv,
- &old_crtc_state->wm.skl.optimal.planes[plane_id],
- &new_crtc_state->wm.skl.optimal.planes[plane_id]))
+ skl_plane_selected_wm_equals(plane,
+ &old_crtc_state->wm.skl.optimal,
+ &new_crtc_state->wm.skl.optimal))
continue;
plane_state = intel_atomic_get_plane_state(state, plane);
ilk_wm_merge(dev_priv, &config, &max, &lp_wm_1_2);
/* 5/6 split only in single pipe config on IVB+ */
- if (INTEL_GEN(dev_priv) >= 7 &&
+ if (DISPLAY_VER(dev_priv) >= 7 &&
config.num_pipes_active == 1 && config.sprites_enabled) {
ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_5_6, &max);
ilk_wm_merge(dev_priv, &config, &max, &lp_wm_5_6);
static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level)
{
- level->plane_en = val & PLANE_WM_EN;
+ level->enable = val & PLANE_WM_EN;
level->ignore_lines = val & PLANE_WM_IGNORE_LINES;
- level->plane_res_b = val & PLANE_WM_BLOCKS_MASK;
- level->plane_res_l = (val >> PLANE_WM_LINES_SHIFT) &
+ level->blocks = val & PLANE_WM_BLOCKS_MASK;
+ level->lines = (val >> PLANE_WM_LINES_SHIFT) &
PLANE_WM_LINES_MASK;
}
skl_wm_level_from_reg_val(val, &wm->wm[level]);
}
- if (INTEL_GEN(dev_priv) >= 12)
- wm->sagv_wm0 = wm->wm[0];
-
if (plane_id != PLANE_CURSOR)
val = intel_uncore_read(&dev_priv->uncore, PLANE_WM_TRANS(pipe, plane_id));
else
val = intel_uncore_read(&dev_priv->uncore, CUR_WM_TRANS(pipe));
skl_wm_level_from_reg_val(val, &wm->trans_wm);
- }
- if (!crtc->active)
- return;
+ if (DISPLAY_VER(dev_priv) >= 12) {
+ wm->sagv.wm0 = wm->wm[0];
+ wm->sagv.trans_wm = wm->trans_wm;
+ }
+ }
}
void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
hw->wm_lp[2] = intel_uncore_read(&dev_priv->uncore, WM3_LP_ILK);
hw->wm_lp_spr[0] = intel_uncore_read(&dev_priv->uncore, WM1S_LP_ILK);
- if (INTEL_GEN(dev_priv) >= 7) {
+ if (DISPLAY_VER(dev_priv) >= 7) {
hw->wm_lp_spr[1] = intel_uncore_read(&dev_priv->uncore, WM2S_LP_IVB);
hw->wm_lp_spr[2] = intel_uncore_read(&dev_priv->uncore, WM3S_LP_IVB);
}
ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL);
/* Wa_1409825376:tgl (pre-prod)*/
- if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1))
+ if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B1))
intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
TGL_VRH_GATING_DIS);
FBC_LLC_FULLY_OPEN);
/* WaDisableSDEUnitClockGating:kbl */
- if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_STEP(dev_priv, 0, STEP_B0))
intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) |
GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/* WaDisableGamClockGating:kbl */
- if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_STEP(dev_priv, 0, STEP_B0))
intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) |
GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
skl_setup_sagv_block_time(dev_priv);
/* For FIFO watermark updates */
- if (INTEL_GEN(dev_priv) >= 9) {
+ if (DISPLAY_VER(dev_priv) >= 9) {
skl_setup_wm_latency(dev_priv);
dev_priv->display.compute_global_watermarks = skl_compute_wm;
} else if (HAS_PCH_SPLIT(dev_priv)) {
ilk_setup_wm_latency(dev_priv);
- if ((IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[1] &&
+ if ((IS_DISPLAY_VER(dev_priv, 5) && dev_priv->wm.pri_latency[1] &&
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
- (!IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[0] &&
+ (!IS_DISPLAY_VER(dev_priv, 5) && dev_priv->wm.pri_latency[0] &&
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
dev_priv->display.compute_intermediate_wm =
dev_priv->display.update_wm = NULL;
} else
dev_priv->display.update_wm = pnv_update_wm;
- } else if (IS_GEN(dev_priv, 4)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 4)) {
dev_priv->display.update_wm = i965_update_wm;
- } else if (IS_GEN(dev_priv, 3)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 3)) {
dev_priv->display.update_wm = i9xx_update_wm;
dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
- } else if (IS_GEN(dev_priv, 2)) {
+ } else if (IS_DISPLAY_VER(dev_priv, 2)) {
if (INTEL_NUM_PIPES(dev_priv) == 1) {
dev_priv->display.update_wm = i845_update_wm;
dev_priv->display.get_fifo_size = i845_get_fifo_size;
goto err;
drm_gem_private_object_init(&i915->drm, &obj->base, size);
- i915_gem_object_init(obj, &fake_ops, &lock_class);
+ i915_gem_object_init(obj, &fake_ops, &lock_class, 0);
i915_gem_object_set_volatile(obj);
obj->cache_level = I915_CACHE_NONE;
/* Preallocate the "backing storage" */
- if (i915_gem_object_pin_pages(obj))
+ if (i915_gem_object_pin_pages_unlocked(obj))
goto err_obj;
i915_gem_object_unpin_pages(obj);
{
struct drm_i915_private *dev_priv = arg;
struct i915_ppgtt *ppgtt;
+ struct i915_gem_ww_ctx ww;
u64 size, last, limit;
int err = 0;
limit = totalram_pages() << PAGE_SHIFT;
limit = min(ppgtt->vm.total, limit);
+ i915_gem_ww_ctx_init(&ww, false);
+ retry:
+ err = i915_vm_lock_objects(&ppgtt->vm, &ww);
+ if (err)
+ goto err_ppgtt_cleanup;
+
/* Check we can allocate the entire range */
for (size = 4096; size <= limit; size <<= 2) {
struct i915_vm_pt_stash stash = {};
}
err_ppgtt_cleanup:
+ if (err == -EDEADLK) {
+ err = i915_gem_ww_ctx_backoff(&ww);
+ if (!err)
+ goto retry;
+ }
+ i915_gem_ww_ctx_fini(&ww);
+
i915_vm_put(&ppgtt->vm);
return err;
}
GEM_BUG_ON(obj->base.size != BIT_ULL(size));
- if (i915_gem_object_pin_pages(obj)) {
+ if (i915_gem_object_pin_pages_unlocked(obj)) {
i915_gem_object_put(obj);
kfree(order);
break;
if (vm->allocate_va_range) {
struct i915_vm_pt_stash stash = {};
+ struct i915_gem_ww_ctx ww;
+ int err;
+
+ i915_gem_ww_ctx_init(&ww, false);
+ retry:
+ err = i915_vm_lock_objects(vm, &ww);
+ if (err)
+ goto alloc_vm_end;
+ err = -ENOMEM;
if (i915_vm_alloc_pt_stash(vm, &stash,
BIT_ULL(size)))
- break;
-
- if (i915_vm_pin_pt_stash(vm, &stash)) {
- i915_vm_free_pt_stash(vm, &stash);
- break;
- }
+ goto alloc_vm_end;
- vm->allocate_va_range(vm, &stash,
- addr, BIT_ULL(size));
+ err = i915_vm_pin_pt_stash(vm, &stash);
+ if (!err)
+ vm->allocate_va_range(vm, &stash,
+ addr, BIT_ULL(size));
i915_vm_free_pt_stash(vm, &stash);
+ alloc_vm_end:
+ if (err == -EDEADLK) {
+ err = i915_gem_ww_ctx_backoff(&ww);
+ if (!err)
+ goto retry;
+ }
+ i915_gem_ww_ctx_fini(&ww);
+
+ if (err)
+ break;
}
mock_vma->pages = obj->mm.pages;
return exercise_ppgtt(arg, shrink_boom);
}
-static int sort_holes(void *priv, struct list_head *A, struct list_head *B)
+static int sort_holes(void *priv, const struct list_head *A,
+ const struct list_head *B)
{
struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack);
struct drm_mm_node *b = list_entry(B, typeof(*b), hole_stack);
if (IS_ERR(obj))
return PTR_ERR(obj);
- err = i915_gem_object_pin_pages(obj);
+ err = i915_gem_object_pin_pages_unlocked(obj);
if (err)
goto out_free;
goto out;
}
- err = i915_gem_object_pin_pages(obj);
+ err = i915_gem_object_pin_pages_unlocked(obj);
if (err) {
i915_gem_object_put(obj);
goto out;
goto out;
}
- err = i915_gem_object_pin_pages(obj);
+ err = i915_gem_object_pin_pages_unlocked(obj);
if (err) {
i915_gem_object_put(obj);
goto out;
goto out;
}
- err = i915_gem_object_pin_pages(obj);
+ err = i915_gem_object_pin_pages_unlocked(obj);
if (err) {
i915_gem_object_put(obj);
goto out;
goto out;
}
- err = i915_gem_object_pin_pages(obj);
+ err = i915_gem_object_pin_pages_unlocked(obj);
if (err) {
i915_gem_object_put(obj);
goto out;
goto out_vm;
}
- batch = i915_gem_object_pin_map(bbe, I915_MAP_WC);
+ batch = i915_gem_object_pin_map_unlocked(bbe, I915_MAP_WC);
if (IS_ERR(batch)) {
err = PTR_ERR(batch);
goto out_put_bbe;
}
/* Track the execution of each request by writing into different slot */
- batch = i915_gem_object_pin_map(act, I915_MAP_WC);
+ batch = i915_gem_object_pin_map_unlocked(act, I915_MAP_WC);
if (IS_ERR(batch)) {
err = PTR_ERR(batch);
goto out_put_act;
goto out_put_out;
GEM_BUG_ON(vma->node.start != vm->total - PAGE_SIZE);
- result = i915_gem_object_pin_map(out, I915_MAP_WB);
+ result = i915_gem_object_pin_map_unlocked(out, I915_MAP_WB);
if (IS_ERR(result)) {
err = PTR_ERR(result);
goto out_put_out;
while (!__igt_timeout(end_time, NULL)) {
struct i915_vm_pt_stash stash = {};
struct i915_request *rq;
+ struct i915_gem_ww_ctx ww;
u64 offset;
offset = igt_random_offset(&prng,
if (err)
goto end;
+ i915_gem_ww_ctx_init(&ww, false);
+ retry:
+ err = i915_vm_lock_objects(vm, &ww);
+ if (err)
+ goto end_ww;
+
err = i915_vm_alloc_pt_stash(vm, &stash, chunk_size);
if (err)
- goto end;
+ goto end_ww;
err = i915_vm_pin_pt_stash(vm, &stash);
- if (err) {
- i915_vm_free_pt_stash(vm, &stash);
- goto end;
- }
-
- vm->allocate_va_range(vm, &stash, offset, chunk_size);
+ if (!err)
+ vm->allocate_va_range(vm, &stash, offset, chunk_size);
i915_vm_free_pt_stash(vm, &stash);
+ end_ww:
+ if (err == -EDEADLK) {
+ err = i915_gem_ww_ctx_backoff(&ww);
+ if (!err)
+ goto retry;
+ }
+ i915_gem_ww_ctx_fini(&ww);
+ if (err)
+ goto end;
/* Prime the TLB with the dummy pages */
for (i = 0; i < count; i++) {
}
static struct devfreq_dev_profile lima_devfreq_profile = {
+ .timer = DEVFREQ_TIMER_DELAYED,
.polling_ms = 50, /* ~3 frames */
.target = lima_devfreq_target,
.get_dev_status = lima_devfreq_get_dev_status,
devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
devfreq->devfreq = NULL;
}
-
- dev_pm_opp_of_remove_table(ldev->dev);
-
- dev_pm_opp_put_regulators(devfreq->regulators_opp_table);
- dev_pm_opp_put_clkname(devfreq->clkname_opp_table);
- devfreq->regulators_opp_table = NULL;
- devfreq->clkname_opp_table = NULL;
}
int lima_devfreq_init(struct lima_device *ldev)
{
struct thermal_cooling_device *cooling;
struct device *dev = ldev->dev;
- struct opp_table *opp_table;
struct devfreq *devfreq;
struct lima_devfreq *ldevfreq = &ldev->devfreq;
struct dev_pm_opp *opp;
spin_lock_init(&ldevfreq->lock);
- opp_table = dev_pm_opp_set_clkname(dev, "core");
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
- goto err_fini;
- }
-
- ldevfreq->clkname_opp_table = opp_table;
-
- opp_table = dev_pm_opp_set_regulators(dev,
- (const char *[]){ "mali" },
- 1);
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
+ ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
+ if (ret) {
/* Continue if the optional regulator is missing */
if (ret != -ENODEV)
- goto err_fini;
- } else {
- ldevfreq->regulators_opp_table = opp_table;
+ return ret;
}
- ret = dev_pm_opp_of_add_table(dev);
+ ret = devm_pm_opp_of_add_table(dev);
if (ret)
- goto err_fini;
+ return ret;
lima_devfreq_reset(ldevfreq);
cur_freq = clk_get_rate(ldev->clk_gpu);
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
- if (IS_ERR(opp)) {
- ret = PTR_ERR(opp);
- goto err_fini;
- }
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
lima_devfreq_profile.initial_freq = cur_freq;
dev_pm_opp_put(opp);
+ /*
+ * Setup default thresholds for the simple_ondemand governor.
+ * The values are chosen based on experiments.
+ */
+ ldevfreq->gov_data.upthreshold = 30;
+ ldevfreq->gov_data.downdifferential = 5;
+
devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile,
- DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
+ DEVFREQ_GOV_SIMPLE_ONDEMAND,
+ &ldevfreq->gov_data);
if (IS_ERR(devfreq)) {
dev_err(dev, "Couldn't initialize GPU devfreq\n");
- ret = PTR_ERR(devfreq);
- goto err_fini;
+ return PTR_ERR(devfreq);
}
ldevfreq->devfreq = devfreq;
ldevfreq->cooling = cooling;
return 0;
-
-err_fini:
- lima_devfreq_fini(ldev);
- return ret;
}
void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
#ifndef __LIMA_DEVFREQ_H__
#define __LIMA_DEVFREQ_H__
+ #include <linux/devfreq.h>
#include <linux/spinlock.h>
#include <linux/ktime.h>
struct devfreq;
-struct opp_table;
struct thermal_cooling_device;
struct lima_device;
struct lima_devfreq {
struct devfreq *devfreq;
- struct opp_table *clkname_opp_table;
- struct opp_table *regulators_opp_table;
struct thermal_cooling_device *cooling;
+ struct devfreq_simple_ondemand_data gov_data;
ktime_t busy_time;
ktime_t idle_time;
unsigned long cur_freq;
struct device *dev = &pfdev->pdev->dev;
struct devfreq *devfreq;
- struct opp_table *opp_table;
struct thermal_cooling_device *cooling;
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
- opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
- pfdev->comp->num_supplies);
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
+ ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
+ pfdev->comp->num_supplies);
+ if (ret) {
/* Continue if the optional regulator is missing */
if (ret != -ENODEV) {
DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
- goto err_fini;
+ return ret;
}
- } else {
- pfdevfreq->regulators_opp_table = opp_table;
}
- ret = dev_pm_opp_of_add_table(dev);
+ ret = devm_pm_opp_of_add_table(dev);
if (ret) {
/* Optional, continue without devfreq */
if (ret == -ENODEV)
ret = 0;
- goto err_fini;
+ return ret;
}
pfdevfreq->opp_of_table_added = true;
cur_freq = clk_get_rate(pfdev->clock);
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
- if (IS_ERR(opp)) {
- ret = PTR_ERR(opp);
- goto err_fini;
- }
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
panfrost_devfreq_profile.initial_freq = cur_freq;
dev_pm_opp_put(opp);
+ /*
+ * Setup default thresholds for the simple_ondemand governor.
+ * The values are chosen based on experiments.
+ */
+ pfdevfreq->gov_data.upthreshold = 45;
+ pfdevfreq->gov_data.downdifferential = 5;
+
devfreq = devm_devfreq_add_device(dev, &panfrost_devfreq_profile,
- DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
+ DEVFREQ_GOV_SIMPLE_ONDEMAND,
+ &pfdevfreq->gov_data);
if (IS_ERR(devfreq)) {
DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
- ret = PTR_ERR(devfreq);
- goto err_fini;
+ return PTR_ERR(devfreq);
}
pfdevfreq->devfreq = devfreq;
pfdevfreq->cooling = cooling;
return 0;
-
-err_fini:
- panfrost_devfreq_fini(pfdev);
- return ret;
}
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
devfreq_cooling_unregister(pfdevfreq->cooling);
pfdevfreq->cooling = NULL;
}
-
- if (pfdevfreq->opp_of_table_added) {
- dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
- pfdevfreq->opp_of_table_added = false;
- }
-
- dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table);
- pfdevfreq->regulators_opp_table = NULL;
}
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
#ifndef __PANFROST_DEVFREQ_H__
#define __PANFROST_DEVFREQ_H__
+ #include <linux/devfreq.h>
#include <linux/spinlock.h>
#include <linux/ktime.h>
struct devfreq;
-struct opp_table;
struct thermal_cooling_device;
struct panfrost_device;
struct panfrost_devfreq {
struct devfreq *devfreq;
- struct opp_table *regulators_opp_table;
struct thermal_cooling_device *cooling;
+ struct devfreq_simple_ondemand_data gov_data;
bool opp_of_table_added;
ktime_t busy_time;
p->dma_reloc_idx = 0;
/* FIXME: we assume that each relocs use 4 dwords */
p->nrelocs = chunk->length_dw / 4;
- p->relocs = kvmalloc_array(p->nrelocs, sizeof(struct radeon_bo_list),
- GFP_KERNEL | __GFP_ZERO);
+ p->relocs = kvcalloc(p->nrelocs, sizeof(struct radeon_bo_list),
+ GFP_KERNEL);
if (p->relocs == NULL) {
return -ENOMEM;
}
p->chunk_relocs = NULL;
p->chunk_flags = NULL;
p->chunk_const_ib = NULL;
- p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
+ p->chunks_array = kvmalloc_array(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
if (p->chunks_array == NULL) {
return -ENOMEM;
}
}
p->cs_flags = 0;
p->nchunks = cs->num_chunks;
- p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL);
+ p->chunks = kvcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL);
if (p->chunks == NULL) {
return -ENOMEM;
}
return 0;
}
-static int cmp_size_smaller_first(void *priv, struct list_head *a,
- struct list_head *b)
+static int cmp_size_smaller_first(void *priv, const struct list_head *a,
+ const struct list_head *b)
{
struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head);
struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head);
kvfree(parser->vm_bos);
for (i = 0; i < parser->nchunks; i++)
kvfree(parser->chunks[i].kdata);
- kfree(parser->chunks);
- kfree(parser->chunks_array);
+ kvfree(parser->chunks);
+ kvfree(parser->chunks_array);
radeon_ib_free(parser->rdev, &parser->ib);
radeon_ib_free(parser->rdev, &parser->const_ib);
}
* @min_initial_entries: Min number of initial intries at cotable allocation
* for this cotable type.
* @size: Size of each entry.
+ * @unbind_func: Unbind call-back function.
*/
struct vmw_cotable_info {
u32 min_initial_entries;
*
* @res: Pointer to the cotable resource.
* @readback: Whether to read back cotable data to the backup buffer.
- * val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
+ * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
* for convenience / fencing.
*
* Unbinds the cotable from the device and fences the backup buffer.
vmw_bo_unreference(&old_buf);
res->id = vcotbl->type;
+ /* Release the pin acquired in vmw_bo_init */
+ ttm_bo_unpin(bo);
+
return 0;
out_map_new:
ttm_bo_kunmap(&old_map);
out_wait:
+ ttm_bo_unpin(bo);
ttm_bo_unreserve(bo);
vmw_bo_unreference(&buf);
#define VMW_MIN_INITIAL_WIDTH 800
#define VMW_MIN_INITIAL_HEIGHT 600
- #ifndef VMWGFX_GIT_VERSION
- #define VMWGFX_GIT_VERSION "Unknown"
- #endif
-
- #define VMWGFX_REPO "In Tree"
-
#define VMWGFX_VALIDATION_MEM_GRAN (16*PAGE_SIZE)
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MSG, \
struct drm_vmw_msg_arg)
- /**
+ /*
* The core DRM version of this macro doesn't account for
* DRM_COMMAND_BASE.
*/
#define VMW_IOCTL_DEF(ioctl, func, flags) \
[DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func}
- /**
+ /*
* Ioctl definitions.
*/
vmw_fifo_release(dev_priv, &dev_priv->fifo);
}
- /**
+ /*
* Sets the initial_[width|height] fields on the given vmw_private.
*
* It does so by reading SVGA_REG_[WIDTH|HEIGHT] regs and then
/**
* vmw_dma_masks - set required page- and dma masks
*
- * @dev: Pointer to struct drm-device
+ * @dev_priv: Pointer to struct drm-device
*
* With 32-bit we can only handle 32 bit PFNs. Optionally set that
* restriction also for 64-bit systems.
dev_priv->last_read_seqno = (uint32_t) -100;
dev_priv->drm.dev_private = dev_priv;
- ret = vmw_setup_pci_resources(dev_priv, pci_id);
- if (ret)
- return ret;
- ret = vmw_detect_version(dev_priv);
- if (ret)
- goto out_no_pci_or_version;
-
mutex_init(&dev_priv->cmdbuf_mutex);
- mutex_init(&dev_priv->release_mutex);
mutex_init(&dev_priv->binding_mutex);
- mutex_init(&dev_priv->global_kms_state_mutex);
ttm_lock_init(&dev_priv->reservation_sem);
spin_lock_init(&dev_priv->resource_lock);
spin_lock_init(&dev_priv->hw_lock);
spin_lock_init(&dev_priv->cap_lock);
spin_lock_init(&dev_priv->cursor_lock);
+ ret = vmw_setup_pci_resources(dev_priv, pci_id);
+ if (ret)
+ return ret;
+ ret = vmw_detect_version(dev_priv);
+ if (ret)
+ goto out_no_pci_or_version;
+
+
for (i = vmw_res_context; i < vmw_res_max; ++i) {
idr_init(&dev_priv->res_idr[i]);
INIT_LIST_HEAD(&dev_priv->res_lru[i]);
drm_vma_offset_manager_init(&dev_priv->vma_manager,
DRM_FILE_PAGE_OFFSET_START,
DRM_FILE_PAGE_OFFSET_SIZE);
- ret = ttm_bo_device_init(&dev_priv->bdev, &vmw_bo_driver,
- dev_priv->drm.dev,
- dev_priv->drm.anon_inode->i_mapping,
- &dev_priv->vma_manager,
- dev_priv->map_mode == vmw_dma_alloc_coherent,
- false);
+ ret = ttm_device_init(&dev_priv->bdev, &vmw_bo_driver,
+ dev_priv->drm.dev,
+ dev_priv->drm.anon_inode->i_mapping,
+ &dev_priv->vma_manager,
+ dev_priv->map_mode == vmw_dma_alloc_coherent,
+ false);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed initializing TTM buffer object driver.\n");
goto out_no_bdev;
if (ret)
goto out_no_fifo;
- DRM_INFO("Atomic: %s\n", (dev_priv->drm.driver->driver_features & DRIVER_ATOMIC)
- ? "yes." : "no.");
if (dev_priv->sm_type == VMW_SM_5)
DRM_INFO("SM5 support available.\n");
if (dev_priv->sm_type == VMW_SM_4_1)
if (dev_priv->sm_type == VMW_SM_4)
DRM_INFO("SM4 support available.\n");
- snprintf(host_log, sizeof(host_log), "vmwgfx: %s-%s",
- VMWGFX_REPO, VMWGFX_GIT_VERSION);
- vmw_host_log(host_log);
-
- memset(host_log, 0, sizeof(host_log));
snprintf(host_log, sizeof(host_log), "vmwgfx: Module Version: %d.%d.%d",
VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
VMWGFX_DRIVER_PATCHLEVEL);
vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR);
vmw_vram_manager_fini(dev_priv);
out_no_vram:
- (void)ttm_bo_device_release(&dev_priv->bdev);
+ ttm_device_fini(&dev_priv->bdev);
out_no_bdev:
vmw_fence_manager_takedown(dev_priv->fman);
out_no_fman:
if (dev_priv->has_mob)
vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB);
vmw_vram_manager_fini(dev_priv);
- (void) ttm_bo_device_release(&dev_priv->bdev);
+ ttm_device_fini(&dev_priv->bdev);
drm_vma_offset_manager_destroy(&dev_priv->vma_manager);
vmw_release_device_late(dev_priv);
vmw_fence_manager_takedown(dev_priv->fman);
{
struct drm_device *dev = pci_get_drvdata(pdev);
+ ttm_mem_global_release(&ttm_mem_glob);
drm_dev_unregister(dev);
vmw_driver_unload(dev);
}
vmw_execbuf_release_pinned_bo(dev_priv);
vmw_resource_evict_all(dev_priv);
vmw_release_device_early(dev_priv);
- while (ttm_bo_swapout(&ctx) == 0);
+ while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0);
if (dev_priv->enable_fb)
vmw_fifo_resource_dec(dev_priv);
if (atomic_read(&dev_priv->num_fifo_resources) != 0) {
if (IS_ERR(vmw))
return PTR_ERR(vmw);
- vmw->drm.pdev = pdev;
pci_set_drvdata(pdev, &vmw->drm);
+ ret = ttm_mem_global_init(&ttm_mem_glob, &pdev->dev);
+ if (ret)
+ return ret;
+
ret = vmw_driver_load(vmw, ent->device);
if (ret)
return ret;
#define VMWGFX_DRIVER_NAME "vmwgfx"
- #define VMWGFX_DRIVER_DATE "20200114"
+ #define VMWGFX_DRIVER_DATE "20210218"
#define VMWGFX_DRIVER_MAJOR 2
#define VMWGFX_DRIVER_MINOR 18
- #define VMWGFX_DRIVER_PATCHLEVEL 0
+ #define VMWGFX_DRIVER_PATCHLEVEL 1
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
#define VMWGFX_MAX_RELOCATIONS 2048
#define VMWGFX_MAX_VALIDATIONS 2048
struct vmw_private {
struct drm_device drm;
- struct ttm_bo_device bdev;
+ struct ttm_device bdev;
struct vmw_fifo_state fifo;
struct vmw_overlay *overlay_priv;
struct drm_property *hotplug_mode_update_property;
struct drm_property *implicit_placement_property;
- struct mutex global_kms_state_mutex;
spinlock_t cursor_lock;
struct drm_atomic_state *suspend_state;
bool refuse_hibernation;
bool suspend_locked;
- struct mutex release_mutex;
atomic_t num_fifo_resources;
/*
struct vmw_buffer_object *new_backup,
unsigned long new_backup_offset);
extern void vmw_query_move_notify(struct ttm_buffer_object *bo,
- struct ttm_resource *mem);
+ struct ttm_resource *old_mem,
+ struct ttm_resource *new_mem);
extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob);
extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo);
extern struct ttm_placement vmw_srf_placement;
extern struct ttm_placement vmw_mob_placement;
extern struct ttm_placement vmw_nonfixed_placement;
- extern struct ttm_bo_driver vmw_bo_driver;
+ extern struct ttm_device_funcs vmw_bo_driver;
extern const struct vmw_sg_table *
vmw_bo_sg_table(struct ttm_buffer_object *bo);
extern int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
struct vmw_buffer_object *tmp_buf = *buf;
*buf = NULL;
- if (tmp_buf != NULL) {
- if (tmp_buf->base.pin_count > 0)
- ttm_bo_unpin(&tmp_buf->base);
+ if (tmp_buf != NULL)
ttm_bo_put(&tmp_buf->base);
- }
}
static inline struct vmw_buffer_object *
struct vmw_piter data_iter,
unsigned long num_data_pages);
+
+static inline void vmw_bo_unpin_unlocked(struct ttm_buffer_object *bo)
+{
+ int ret = ttm_bo_reserve(bo, false, true, NULL);
+ BUG_ON(ret != 0);
+ ttm_bo_unpin(bo);
+ ttm_bo_unreserve(bo);
+}
+
+
/*
* vmw_setup_otable_base - Issue an object table base setup command to
* the device
&batch->otables[i]);
}
- ttm_bo_unpin(batch->otable_bo);
+ vmw_bo_unpin_unlocked(batch->otable_bo);
ttm_bo_put(batch->otable_bo);
batch->otable_bo = NULL;
return ret;
BUG_ON(ret != 0);
vmw_bo_fence_single(bo, NULL);
+ ttm_bo_unpin(bo);
ttm_bo_unreserve(bo);
+ ttm_bo_unpin(batch->otable_bo);
ttm_bo_put(batch->otable_bo);
batch->otable_bo = NULL;
}
void vmw_mob_destroy(struct vmw_mob *mob)
{
if (mob->pt_bo) {
- ttm_bo_unpin(mob->pt_bo);
+ vmw_bo_unpin_unlocked(mob->pt_bo);
ttm_bo_put(mob->pt_bo);
mob->pt_bo = NULL;
}
out_no_cmd_space:
vmw_fifo_resource_dec(dev_priv);
if (pt_set_up) {
- ttm_bo_unpin(mob->pt_bo);
+ vmw_bo_unpin_unlocked(mob->pt_bo);
ttm_bo_put(mob->pt_bo);
mob->pt_bo = NULL;
}
{
const struct v4l2_fmtdesc *p = arg;
- pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, mbus_code=0x%04x, description='%.*s'\n",
+ pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%p4cc, mbus_code=0x%04x, description='%.*s'\n",
p->index, prt_names(p->type, v4l2_type_names),
- p->flags, (p->pixelformat & 0xff),
- (p->pixelformat >> 8) & 0xff,
- (p->pixelformat >> 16) & 0xff,
- (p->pixelformat >> 24) & 0xff,
- p->mbus_code,
+ p->flags, &p->pixelformat, p->mbus_code,
(int)sizeof(p->description), p->description);
}
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
pix = &p->fmt.pix;
- pr_cont(", width=%u, height=%u, pixelformat=%c%c%c%c, field=%s, bytesperline=%u, sizeimage=%u, colorspace=%d, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n",
- pix->width, pix->height,
- (pix->pixelformat & 0xff),
- (pix->pixelformat >> 8) & 0xff,
- (pix->pixelformat >> 16) & 0xff,
- (pix->pixelformat >> 24) & 0xff,
+ pr_cont(", width=%u, height=%u, pixelformat=%p4cc, field=%s, bytesperline=%u, sizeimage=%u, colorspace=%d, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n",
+ pix->width, pix->height, &pix->pixelformat,
prt_names(pix->field, v4l2_field_names),
pix->bytesperline, pix->sizeimage,
pix->colorspace, pix->flags, pix->ycbcr_enc,
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
mp = &p->fmt.pix_mp;
- pr_cont(", width=%u, height=%u, format=%c%c%c%c, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n",
- mp->width, mp->height,
- (mp->pixelformat & 0xff),
- (mp->pixelformat >> 8) & 0xff,
- (mp->pixelformat >> 16) & 0xff,
- (mp->pixelformat >> 24) & 0xff,
+ pr_cont(", width=%u, height=%u, format=%p4cc, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n",
+ mp->width, mp->height, &mp->pixelformat,
prt_names(mp->field, v4l2_field_names),
mp->colorspace, mp->num_planes, mp->flags,
mp->ycbcr_enc, mp->quantization, mp->xfer_func);
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
vbi = &p->fmt.vbi;
- pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n",
+ pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%p4cc, start=%u,%u, count=%u,%u\n",
vbi->sampling_rate, vbi->offset,
- vbi->samples_per_line,
- (vbi->sample_format & 0xff),
- (vbi->sample_format >> 8) & 0xff,
- (vbi->sample_format >> 16) & 0xff,
- (vbi->sample_format >> 24) & 0xff,
+ vbi->samples_per_line, &vbi->sample_format,
vbi->start[0], vbi->start[1],
vbi->count[0], vbi->count[1]);
break;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
sdr = &p->fmt.sdr;
- pr_cont(", pixelformat=%c%c%c%c\n",
- (sdr->pixelformat >> 0) & 0xff,
- (sdr->pixelformat >> 8) & 0xff,
- (sdr->pixelformat >> 16) & 0xff,
- (sdr->pixelformat >> 24) & 0xff);
+ pr_cont(", pixelformat=%p4cc\n", &sdr->pixelformat);
break;
case V4L2_BUF_TYPE_META_CAPTURE:
case V4L2_BUF_TYPE_META_OUTPUT:
meta = &p->fmt.meta;
- pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n",
- (meta->dataformat >> 0) & 0xff,
- (meta->dataformat >> 8) & 0xff,
- (meta->dataformat >> 16) & 0xff,
- (meta->dataformat >> 24) & 0xff,
- meta->buffersize);
+ pr_cont(", dataformat=%p4cc, buffersize=%u\n",
+ &meta->dataformat, meta->buffersize);
break;
}
}
{
const struct v4l2_framebuffer *p = arg;
- pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, height=%u, pixelformat=%c%c%c%c, bytesperline=%u, sizeimage=%u, colorspace=%d\n",
- p->capability, p->flags, p->base,
- p->fmt.width, p->fmt.height,
- (p->fmt.pixelformat & 0xff),
- (p->fmt.pixelformat >> 8) & 0xff,
- (p->fmt.pixelformat >> 16) & 0xff,
- (p->fmt.pixelformat >> 24) & 0xff,
- p->fmt.bytesperline, p->fmt.sizeimage,
- p->fmt.colorspace);
+ pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, height=%u, pixelformat=%p4cc, bytesperline=%u, sizeimage=%u, colorspace=%d\n",
+ p->capability, p->flags, p->base, p->fmt.width, p->fmt.height,
+ &p->fmt.pixelformat, p->fmt.bytesperline, p->fmt.sizeimage,
+ p->fmt.colorspace);
}
static void v4l_print_buftype(const void *arg, bool write_only)
const struct v4l2_plane *plane;
int i;
- pr_cont("%02d:%02d:%02d.%09ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
+ pr_cont("%02d:%02d:%02d.%06ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
(int)p->timestamp.tv_sec / 3600,
((int)p->timestamp.tv_sec / 60) % 60,
((int)p->timestamp.tv_sec % 60),
{
const struct v4l2_frmsizeenum *p = arg;
- pr_cont("index=%u, pixelformat=%c%c%c%c, type=%u",
- p->index,
- (p->pixel_format & 0xff),
- (p->pixel_format >> 8) & 0xff,
- (p->pixel_format >> 16) & 0xff,
- (p->pixel_format >> 24) & 0xff,
- p->type);
+ pr_cont("index=%u, pixelformat=%p4cc, type=%u",
+ p->index, &p->pixel_format, p->type);
switch (p->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
pr_cont(", wxh=%ux%u\n",
{
const struct v4l2_frmivalenum *p = arg;
- pr_cont("index=%u, pixelformat=%c%c%c%c, wxh=%ux%u, type=%u",
- p->index,
- (p->pixel_format & 0xff),
- (p->pixel_format >> 8) & 0xff,
- (p->pixel_format >> 16) & 0xff,
- (p->pixel_format >> 24) & 0xff,
- p->width, p->height, p->type);
+ pr_cont("index=%u, pixelformat=%p4cc, wxh=%ux%u, type=%u",
+ p->index, &p->pixel_format, p->width, p->height, p->type);
switch (p->type) {
case V4L2_FRMIVAL_TYPE_DISCRETE:
pr_cont(", fps=%d/%d\n",
case V4L2_PIX_FMT_YUV444: descr = "16-bit A/XYUV 4-4-4-4"; break;
case V4L2_PIX_FMT_YUV555: descr = "16-bit A/XYUV 1-5-5-5"; break;
case V4L2_PIX_FMT_YUV565: descr = "16-bit YUV 5-6-5"; break;
+ case V4L2_PIX_FMT_YUV24: descr = "24-bit YUV 4:4:4 8-8-8"; break;
case V4L2_PIX_FMT_YUV32: descr = "32-bit A/XYUV 8-8-8-8"; break;
case V4L2_PIX_FMT_AYUV32: descr = "32-bit AYUV 8-8-8-8"; break;
case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break;
return;
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
flags = 0;
- snprintf(fmt->description, sz, "%c%c%c%c%s",
- (char)(fmt->pixelformat & 0x7f),
- (char)((fmt->pixelformat >> 8) & 0x7f),
- (char)((fmt->pixelformat >> 16) & 0x7f),
- (char)((fmt->pixelformat >> 24) & 0x7f),
- (fmt->pixelformat & (1UL << 31)) ? "-BE" : "");
+ snprintf(fmt->description, sz, "%p4cc",
+ &fmt->pixelformat);
break;
}
}
{
}
+struct page_flags_test {
+ int width;
+ int shift;
+ int mask;
+ unsigned long value;
+ const char *fmt;
+ const char *name;
+};
+
+static struct page_flags_test pft[] = {
+ {SECTIONS_WIDTH, SECTIONS_PGSHIFT, SECTIONS_MASK,
+ 0, "%d", "section"},
+ {NODES_WIDTH, NODES_PGSHIFT, NODES_MASK,
+ 0, "%d", "node"},
+ {ZONES_WIDTH, ZONES_PGSHIFT, ZONES_MASK,
+ 0, "%d", "zone"},
+ {LAST_CPUPID_WIDTH, LAST_CPUPID_PGSHIFT, LAST_CPUPID_MASK,
+ 0, "%#x", "lastcpupid"},
+ {KASAN_TAG_WIDTH, KASAN_TAG_PGSHIFT, KASAN_TAG_MASK,
+ 0, "%#x", "kasantag"},
+};
+
+static void __init
+page_flags_test(int section, int node, int zone, int last_cpupid,
+ int kasan_tag, int flags, const char *name, char *cmp_buf)
+{
+ unsigned long values[] = {section, node, zone, last_cpupid, kasan_tag};
+ unsigned long page_flags = 0;
+ unsigned long size = 0;
+ bool append = false;
+ int i;
+
+ flags &= BIT(NR_PAGEFLAGS) - 1;
+ if (flags) {
+ page_flags |= flags;
+ snprintf(cmp_buf + size, BUF_SIZE - size, "%s", name);
+ size = strlen(cmp_buf);
+#if SECTIONS_WIDTH || NODES_WIDTH || ZONES_WIDTH || \
+ LAST_CPUPID_WIDTH || KASAN_TAG_WIDTH
+ /* Other information also included in page flags */
+ snprintf(cmp_buf + size, BUF_SIZE - size, "|");
+ size = strlen(cmp_buf);
+#endif
+ }
+
+ /* Set the test value */
+ for (i = 0; i < ARRAY_SIZE(pft); i++)
+ pft[i].value = values[i];
+
+ for (i = 0; i < ARRAY_SIZE(pft); i++) {
+ if (!pft[i].width)
+ continue;
+
+ if (append) {
+ snprintf(cmp_buf + size, BUF_SIZE - size, "|");
+ size = strlen(cmp_buf);
+ }
+
+ page_flags |= (pft[i].value & pft[i].mask) << pft[i].shift;
+ snprintf(cmp_buf + size, BUF_SIZE - size, "%s=", pft[i].name);
+ size = strlen(cmp_buf);
+ snprintf(cmp_buf + size, BUF_SIZE - size, pft[i].fmt,
+ pft[i].value & pft[i].mask);
+ size = strlen(cmp_buf);
+ append = true;
+ }
+
+ test(cmp_buf, "%pGp", &page_flags);
+}
+
static void __init
flags(void)
{
unsigned long flags;
- gfp_t gfp;
char *cmp_buffer;
+ gfp_t gfp;
+
+ cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
+ if (!cmp_buffer)
+ return;
flags = 0;
- test("", "%pGp", &flags);
+ page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
- /* Page flags should filter the zone id */
flags = 1UL << NR_PAGEFLAGS;
- test("", "%pGp", &flags);
+ page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
| 1UL << PG_active | 1UL << PG_swapbacked;
- test("uptodate|dirty|lru|active|swapbacked", "%pGp", &flags);
-
+ page_flags_test(1, 1, 1, 0x1fffff, 1, flags,
+ "uptodate|dirty|lru|active|swapbacked",
+ cmp_buffer);
flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC
| VM_DENYWRITE;
gfp = __GFP_ATOMIC;
test("__GFP_ATOMIC", "%pGg", &gfp);
- cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
- if (!cmp_buffer)
- return;
-
/* Any flags not translated by the table should remain numeric */
gfp = ~__GFP_BITS_MASK;
snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp);
software_node_unregister_nodes(softnodes);
}
+ static void __init fourcc_pointer(void)
+ {
+ struct {
+ u32 code;
+ char *str;
+ } const try[] = {
+ { 0x3231564e, "NV12 little-endian (0x3231564e)", },
+ { 0xb231564e, "NV12 big-endian (0xb231564e)", },
+ { 0x10111213, ".... little-endian (0x10111213)", },
+ { 0x20303159, "Y10 little-endian (0x20303159)", },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(try); i++)
+ test(try[i].str, "%p4cc", &try[i].code);
+ }
+
static void __init
errptr(void)
{
flags();
errptr();
fwnode_pointer();
+ fourcc_pointer();
}
static void __init selftest(void)
return special_hex_number(buf, end, num, size);
}
+ static noinline_for_stack
+ char *fourcc_string(char *buf, char *end, const u32 *fourcc,
+ struct printf_spec spec, const char *fmt)
+ {
+ char output[sizeof("0123 little-endian (0x01234567)")];
+ char *p = output;
+ unsigned int i;
+ u32 val;
+
+ if (fmt[1] != 'c' || fmt[2] != 'c')
+ return error_string(buf, end, "(%p4?)", spec);
+
+ if (check_pointer(&buf, end, fourcc, spec))
+ return buf;
+
+ val = *fourcc & ~BIT(31);
+
+ for (i = 0; i < sizeof(*fourcc); i++) {
+ unsigned char c = val >> (i * 8);
+
+ /* Print non-control ASCII characters as-is, dot otherwise */
+ *p++ = isascii(c) && isprint(c) ? c : '.';
+ }
+
+ strcpy(p, *fourcc & BIT(31) ? " big-endian" : " little-endian");
+ p += strlen(p);
+
+ *p++ = ' ';
+ *p++ = '(';
+ p = special_hex_number(p, output + sizeof(output) - 2, *fourcc, sizeof(u32));
+ *p++ = ')';
+ *p = '\0';
+
+ return string(buf, end, output, spec);
+ }
+
static noinline_for_stack
char *address_val(char *buf, char *end, const void *addr,
struct printf_spec spec, const char *fmt)
return buf;
}
+struct page_flags_fields {
+ int width;
+ int shift;
+ int mask;
+ const struct printf_spec *spec;
+ const char *name;
+};
+
+static const struct page_flags_fields pff[] = {
+ {SECTIONS_WIDTH, SECTIONS_PGSHIFT, SECTIONS_MASK,
+ &default_dec_spec, "section"},
+ {NODES_WIDTH, NODES_PGSHIFT, NODES_MASK,
+ &default_dec_spec, "node"},
+ {ZONES_WIDTH, ZONES_PGSHIFT, ZONES_MASK,
+ &default_dec_spec, "zone"},
+ {LAST_CPUPID_WIDTH, LAST_CPUPID_PGSHIFT, LAST_CPUPID_MASK,
+ &default_flag_spec, "lastcpupid"},
+ {KASAN_TAG_WIDTH, KASAN_TAG_PGSHIFT, KASAN_TAG_MASK,
+ &default_flag_spec, "kasantag"},
+};
+
+static
+char *format_page_flags(char *buf, char *end, unsigned long flags)
+{
+ unsigned long main_flags = flags & (BIT(NR_PAGEFLAGS) - 1);
+ bool append = false;
+ int i;
+
+ /* Page flags from the main area. */
+ if (main_flags) {
+ buf = format_flags(buf, end, main_flags, pageflag_names);
+ append = true;
+ }
+
+ /* Page flags from the fields area */
+ for (i = 0; i < ARRAY_SIZE(pff); i++) {
+ /* Skip undefined fields. */
+ if (!pff[i].width)
+ continue;
+
+ /* Format: Flag Name + '=' (equals sign) + Number + '|' (separator) */
+ if (append) {
+ if (buf < end)
+ *buf = '|';
+ buf++;
+ }
+
+ buf = string(buf, end, pff[i].name, default_str_spec);
+ if (buf < end)
+ *buf = '=';
+ buf++;
+ buf = number(buf, end, (flags >> pff[i].shift) & pff[i].mask,
+ *pff[i].spec);
+
+ append = true;
+ }
+
+ return buf;
+}
+
static noinline_for_stack
char *flags_string(char *buf, char *end, void *flags_ptr,
struct printf_spec spec, const char *fmt)
switch (fmt[1]) {
case 'p':
- flags = *(unsigned long *)flags_ptr;
- /* Remove zone id */
- flags &= (1UL << NR_PAGEFLAGS) - 1;
- names = pageflag_names;
- break;
+ return format_page_flags(buf, end, *(unsigned long *)flags_ptr);
case 'v':
flags = *(unsigned long *)flags_ptr;
names = vmaflag_names;
static int __init no_hash_pointers_enable(char *str)
{
+ if (no_hash_pointers)
+ return 0;
+
no_hash_pointers = true;
pr_warn("**********************************************************\n");
* Implements a "recursive vsnprintf".
* Do not use this feature without some mechanism to verify the
* correctness of the format string and va_list arguments.
- * - 'K' For a kernel pointer that should be hidden from unprivileged users
+ * - 'K' For a kernel pointer that should be hidden from unprivileged users.
+ * Use only for procfs, sysfs and similar files, not printk(); please
+ * read the documentation (path below) first.
* - 'NF' For a netdev_features_t
+ * - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value.
* - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
* a certain separator (' ' by default):
* C colon
* Without an option prints the full name of the node
* f full name
* P node name, including a possible unit address
- * - 'x' For printing the address. Equivalent to "%lx".
+ * - 'x' For printing the address unmodified. Equivalent to "%lx".
+ * Please read the documentation (path below) before using!
* - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
* bpf_trace_printk() where [ku] prefix specifies either kernel (k)
* or user (u) memory to probe, and:
return restricted_pointer(buf, end, ptr, spec);
case 'N':
return netdev_bits(buf, end, ptr, spec, fmt);
+ case '4':
+ return fourcc_string(buf, end, ptr, spec, fmt);
case 'a':
return address_val(buf, end, ptr, spec, fmt);
case 'd':
switch (*fmt) {
case 'S':
case 's':
- case 'F':
- case 'f':
case 'x':
case 'K':
case 'e':
use Getopt::Long qw(:config no_auto_abbrev);
my $quiet = 0;
+my $verbose = 0;
+my %verbose_messages = ();
+my %verbose_emitted = ();
my $tree = 1;
my $chk_signoff = 1;
my $chk_patch = 1;
my $codespell = 0;
my $codespellfile = "/usr/share/codespell/dictionary.txt";
my $conststructsfile = "$D/const_structs.checkpatch";
+my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst";
my $typedefsfile;
my $color = "auto";
my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE
Options:
-q, --quiet quiet
+ -v, --verbose verbose mode
--no-tree run without a kernel tree
--no-signoff do not check for 'Signed-off-by' line
--patch treat FILE as patchfile (default)
my $text = <$script>;
close($script);
- my @types = ();
+ my %types = ();
# Also catch when type or level is passed through a variable
- for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
- push (@types, $_);
+ while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
+ if (defined($1)) {
+ if (exists($types{$2})) {
+ $types{$2} .= ",$1" if ($types{$2} ne $1);
+ } else {
+ $types{$2} = $1;
+ }
+ } else {
+ $types{$2} = "UNDETERMINED";
+ }
}
- @types = sort(uniq(@types));
+
print("#\tMessage type\n\n");
- foreach my $type (@types) {
+ if ($color) {
+ print(" ( Color coding: ");
+ print(RED . "ERROR" . RESET);
+ print(" | ");
+ print(YELLOW . "WARNING" . RESET);
+ print(" | ");
+ print(GREEN . "CHECK" . RESET);
+ print(" | ");
+ print("Multiple levels / Undetermined");
+ print(" )\n\n");
+ }
+
+ foreach my $type (sort keys %types) {
+ my $orig_type = $type;
+ if ($color) {
+ my $level = $types{$type};
+ if ($level eq "ERROR") {
+ $type = RED . $type . RESET;
+ } elsif ($level eq "WARN") {
+ $type = YELLOW . $type . RESET;
+ } elsif ($level eq "CHK") {
+ $type = GREEN . $type . RESET;
+ }
+ }
print(++$count . "\t" . $type . "\n");
+ if ($verbose && exists($verbose_messages{$orig_type})) {
+ my $message = $verbose_messages{$orig_type};
+ $message =~ s/\n/\n\t/g;
+ print("\t" . $message . "\n\n");
+ }
}
exit($exitcode);
unshift(@ARGV, @conf_args) if @conf_args;
}
+sub load_docs {
+ open(my $docs, '<', "$docsfile")
+ or warn "$P: Can't read the documentation file $docsfile $!\n";
+
+ my $type = '';
+ my $desc = '';
+ my $in_desc = 0;
+
+ while (<$docs>) {
+ chomp;
+ my $line = $_;
+ $line =~ s/\s+$//;
+
+ if ($line =~ /^\s*\*\*(.+)\*\*$/) {
+ if ($desc ne '') {
+ $verbose_messages{$type} = trim($desc);
+ }
+ $type = $1;
+ $desc = '';
+ $in_desc = 1;
+ } elsif ($in_desc) {
+ if ($line =~ /^(?:\s{4,}|$)/) {
+ $line =~ s/^\s{4}//;
+ $desc .= $line;
+ $desc .= "\n";
+ } else {
+ $verbose_messages{$type} = trim($desc);
+ $type = '';
+ $desc = '';
+ $in_desc = 0;
+ }
+ }
+ }
+
+ if ($desc ne '') {
+ $verbose_messages{$type} = trim($desc);
+ }
+ close($docs);
+}
+
# Perl's Getopt::Long allows options to take optional arguments after a space.
# Prevent --color by itself from consuming other arguments
foreach (@ARGV) {
GetOptions(
'q|quiet+' => \$quiet,
+ 'v|verbose!' => \$verbose,
'tree!' => \$tree,
'signoff!' => \$chk_signoff,
'patch!' => \$chk_patch,
help(0) if ($help);
+die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
+die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
+
+if ($color =~ /^[01]$/) {
+ $color = !$color;
+} elsif ($color =~ /^always$/i) {
+ $color = 1;
+} elsif ($color =~ /^never$/i) {
+ $color = 0;
+} elsif ($color =~ /^auto$/i) {
+ $color = (-t STDOUT);
+} else {
+ die "$P: Invalid color mode: $color\n";
+}
+
+load_docs() if ($verbose);
list_types(0) if ($list_types);
$fix = 1 if ($fix_inplace);
$check_orig = $check;
-die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
-
my $exit = 0;
my $perl_version_ok = 1;
push(@ARGV, '-');
}
-if ($color =~ /^[01]$/) {
- $color = !$color;
-} elsif ($color =~ /^always$/i) {
- $color = 1;
-} elsif ($color =~ /^never$/i) {
- $color = 0;
-} elsif ($color =~ /^auto$/i) {
- $color = (-t STDOUT);
-} else {
- die "$P: Invalid color mode: $color\n";
-}
-
# skip TAB size 1 to avoid additional checks on $tabsize - 1
die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2);
splice(@lines, 1, 1);
$output = join("\n", @lines);
}
- $output = (split('\n', $output))[0] . "\n" if ($terse);
+
+ if ($terse) {
+ $output = (split('\n', $output))[0] . "\n";
+ }
+
+ if ($verbose && exists($verbose_messages{$type}) &&
+ !exists($verbose_emitted{$type})) {
+ $output .= $verbose_messages{$type} . "\n\n";
+ $verbose_emitted{$type} = 1;
+ }
push(our @report, $output);
$specifier = $1;
$extension = $2;
$qualifier = $3;
- if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
+ if ($extension !~ /[4SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
($extension eq "f" &&
- defined $qualifier && $qualifier !~ /^w/)) {
+ defined $qualifier && $qualifier !~ /^w/) ||
+ ($extension eq "4" &&
+ defined $qualifier && $qualifier !~ /^cc/)) {
$bad_specifier = $specifier;
last;
}