diff --git a/0000-raspberrypi-kernel.patch b/0000-raspberrypi-kernel.patch index 44d271c..45d7a3e 100644 --- a/0000-raspberrypi-kernel.patch +++ b/0000-raspberrypi-kernel.patch @@ -1,10 +1,13 @@ -From 42a6a0e9bca5d03c3bbc4104eb93025153d4cfee Mon Sep 17 00:00:00 2001 +From 46ff512235e3c700f5fc47176a020c251fb2e1d7 Mon Sep 17 00:00:00 2001 From: Yafen -Date: Wed, 15 May 2024 06:23:21 +0800 -Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) +Date: Mon, 2 Dec 2024 18:11:39 +0800 +Subject: [PATCH] apply RPi patch of 6.6.59 (openEuler 6.6.0-60.0.0) --- .../admin-guide/media/bcm2835-isp.rst | 127 + + .../admin-guide/media/raspberrypi-pisp-be.dot | 20 + + .../admin-guide/media/raspberrypi-pisp-be.rst | 109 + + .../admin-guide/media/v4l-drivers.rst | 1 + .../bindings/display/brcm,bcm2711-hdmi.yaml | 2 + .../bindings/display/brcm,bcm2835-dsi0.yaml | 1 + .../bindings/display/brcm,bcm2835-hvs.yaml | 5 +- @@ -28,7 +31,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../bindings/media/i2c/ovti,ov64a40.yaml | 98 + .../bindings/media/i2c/rohm,bu64754.yaml | 48 + .../i2c/{imx258.yaml => sony,imx258.yaml} | 9 +- + .../bindings/media/i2c/sony,imx500.yaml | 132 + .../bindings/media/i2c/sony,imx708.yaml | 128 + + .../bindings/media/raspberrypi,pispbe.yaml | 63 + .../bindings/media/rpivid_hevc.yaml | 72 + .../bindings/misc/brcm,bcm2835-smi-dev.txt | 17 + .../bindings/misc/brcm,bcm2835-smi.txt | 48 + @@ -42,73 +47,73 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../devicetree/bindings/rtc/rtc-rpi.txt | 22 + .../devicetree/bindings/serial/pl011.yaml | 6 + .../devicetree/bindings/sound/pcm512x.txt | 9 +- + .../bindings/sound/snps,designware-i2s.yaml | 4 + + .../spi/raspberrypi,rp2040-gpio-bridge.yaml | 77 + .../devicetree/bindings/spi/spi-gpio.yaml | 4 + .../devicetree/bindings/usb/snps,dwc3.yaml | 9 +- .../devicetree/bindings/vendor-prefixes.txt | 463 ++ .../devicetree/bindings/vendor-prefixes.yaml | 6 + .../devicetree/configfs-overlays.txt | 31 + - Documentation/driver-api/pwm.rst | 17 +- + .../driver-api/gpio/drivers-on-gpio.rst | 7 +- + Documentation/driver-api/pwm.rst | 9 + .../userspace-api/media/drivers/index.rst | 1 + - .../userspace-api/media/v4l/meta-formats.rst | 2 + + .../userspace-api/media/v4l/meta-formats.rst | 3 + + .../media/v4l/metafmt-pisp-be.rst | 56 + + .../userspace-api/media/v4l/pixfmt-bayer.rst | 1 + .../v4l/pixfmt-meta-bcm2835-isp-stats.rst | 41 + .../media/v4l/pixfmt-meta-sensor-data.rst | 32 + .../media/v4l/pixfmt-nv12-col128.rst | 215 + + .../userspace-api/media/v4l/pixfmt-rgb.rst | 54 + + .../media/v4l/pixfmt-srggb8-pisp-comp.rst | 74 + .../userspace-api/media/v4l/pixfmt-y12p.rst | 45 + .../userspace-api/media/v4l/pixfmt-y14p.rst | 54 + + .../media/v4l/pixfmt-yuv-luma.rst | 4 + .../media/v4l/pixfmt-yuv-planar.rst | 12 + .../media/v4l/subdev-formats.rst | 143 + .../userspace-api/media/v4l/yuv-formats.rst | 21 + - MAINTAINERS | 83 +- + MAINTAINERS | 105 +- README.md | 30 + arch/arm/boot/dts/Makefile | 5 + arch/arm/boot/dts/broadcom/Makefile | 35 + .../boot/dts/broadcom/bcm2708-rpi-b-plus.dts | 210 + .../boot/dts/broadcom/bcm2708-rpi-b-rev1.dts | 223 + arch/arm/boot/dts/broadcom/bcm2708-rpi-b.dts | 198 + - .../arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi | 38 + + .../arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi | 42 + arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dts | 174 + - .../arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi | 27 + - .../boot/dts/broadcom/bcm2708-rpi-zero-w.dts | 254 + + .../arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi | 23 + + .../boot/dts/broadcom/bcm2708-rpi-zero-w.dts | 250 + .../boot/dts/broadcom/bcm2708-rpi-zero.dts | 189 + - arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi | 57 + + arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi | 63 + arch/arm/boot/dts/broadcom/bcm2708.dtsi | 19 + .../arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts | 204 + - .../arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts | 219 + + .../arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts | 215 + arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi | 8 + arch/arm/boot/dts/broadcom/bcm2709.dtsi | 29 + - arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi | 201 + + arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi | 208 + arch/arm/boot/dts/broadcom/bcm270x.dtsi | 294 + .../arm/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 204 + - .../dts/broadcom/bcm2710-rpi-3-b-plus.dts | 299 + - .../arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts | 297 + - .../arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 219 + - .../dts/broadcom/bcm2710-rpi-zero-2-w.dts | 261 + + .../dts/broadcom/bcm2710-rpi-3-b-plus.dts | 295 + + .../arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts | 293 + + .../arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 215 + + .../dts/broadcom/bcm2710-rpi-zero-2-w.dts | 257 + .../boot/dts/broadcom/bcm2710-rpi-zero-2.dts | 1 + arch/arm/boot/dts/broadcom/bcm2710.dtsi | 32 + - .../arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts | 262 +- + .../arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts | 258 +- .../arm/boot/dts/broadcom/bcm2711-rpi-400.dts | 49 +- - .../arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 510 ++ - .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 298 + - .../arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 561 ++ + .../arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts | 499 ++ + .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 293 + + .../arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi | 567 ++ arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi | 13 + arch/arm/boot/dts/broadcom/bcm2711.dtsi | 2 +- - .../arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 863 ++ - .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 20 + - .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 10 + - .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 888 ++ - arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi | 337 + - arch/arm/boot/dts/broadcom/bcm2712.dtsi | 1304 +++ - .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 107 + - .../arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi | 38 + + .../arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi | 42 + .../dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi | 4 + .../dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi | 4 + .../dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi | 4 + .../broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi | 4 + .../broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi | 4 + - arch/arm/boot/dts/broadcom/bcm283x.dtsi | 4 +- - arch/arm/boot/dts/broadcom/rp1.dtsi | 1307 +++ - arch/arm/boot/dts/overlays/Makefile | 336 + - arch/arm/boot/dts/overlays/README | 5389 +++++++++++++ + arch/arm/boot/dts/broadcom/bcm283x.dtsi | 8 +- + arch/arm/boot/dts/overlays/Makefile | 347 + + arch/arm/boot/dts/overlays/README | 5516 +++++++++++++ .../arm/boot/dts/overlays/act-led-overlay.dts | 28 + .../dts/overlays/adafruit-st7735r-overlay.dts | 83 + .../boot/dts/overlays/adafruit18-overlay.dts | 55 + @@ -190,9 +195,12 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../boot/dts/overlays/gpio-no-irq-overlay.dts | 14 + .../dts/overlays/gpio-poweroff-overlay.dts | 39 + .../dts/overlays/gpio-shutdown-overlay.dts | 86 + - arch/arm/boot/dts/overlays/hat_map.dts | 98 + + arch/arm/boot/dts/overlays/hat_map.dts | 124 + + .../dts/overlays/hd44780-i2c-lcd-overlay.dts | 57 + .../boot/dts/overlays/hd44780-lcd-overlay.dts | 46 + .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 + + .../dts/overlays/hifiberry-adc-overlay.dts | 45 + + .../dts/overlays/hifiberry-adc8x-overlay.dts | 50 + .../dts/overlays/hifiberry-amp-overlay.dts | 39 + .../dts/overlays/hifiberry-amp100-overlay.dts | 67 + .../dts/overlays/hifiberry-amp3-overlay.dts | 57 + @@ -235,6 +243,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm/boot/dts/overlays/i2c6-overlay.dts | 34 + .../arm/boot/dts/overlays/i2s-dac-overlay.dts | 34 + .../dts/overlays/i2s-gpio28-31-overlay.dts | 18 + + .../dts/overlays/i2s-master-dac-overlay.dts | 50 + .../boot/dts/overlays/ilitek251x-overlay.dts | 45 + arch/arm/boot/dts/overlays/imx219-overlay.dts | 89 + arch/arm/boot/dts/overlays/imx219.dtsi | 27 + @@ -250,6 +259,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm/boot/dts/overlays/imx477-overlay.dts | 17 + .../boot/dts/overlays/imx477_378-overlay.dtsi | 92 + arch/arm/boot/dts/overlays/imx477_378.dtsi | 24 + + arch/arm/boot/dts/overlays/imx500-overlay.dts | 122 + + .../boot/dts/overlays/imx500-pi5-overlay.dts | 127 + + arch/arm/boot/dts/overlays/imx500.dtsi | 28 + arch/arm/boot/dts/overlays/imx519-overlay.dts | 93 + arch/arm/boot/dts/overlays/imx519.dtsi | 34 + arch/arm/boot/dts/overlays/imx708-overlay.dts | 105 + @@ -308,12 +320,13 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm/boot/dts/overlays/ov7251.dtsi | 28 + arch/arm/boot/dts/overlays/ov9281-overlay.dts | 78 + arch/arm/boot/dts/overlays/ov9281.dtsi | 27 + - arch/arm/boot/dts/overlays/overlay_map.dts | 493 ++ + arch/arm/boot/dts/overlays/overlay_map.dts | 514 ++ .../arm/boot/dts/overlays/papirus-overlay.dts | 84 + .../arm/boot/dts/overlays/pca953x-overlay.dts | 240 + .../arm/boot/dts/overlays/pcf857x-overlay.dts | 32 + .../dts/overlays/pcie-32bit-dma-overlay.dts | 38 + .../overlays/pcie-32bit-dma-pi5-overlay.dts | 26 + + .../overlays/pciex1-compat-pi5-overlay.dts | 40 + arch/arm/boot/dts/overlays/pibell-overlay.dts | 81 + .../dts/overlays/pifacedigital-overlay.dts | 144 + .../arm/boot/dts/overlays/pifi-40-overlay.dts | 50 + @@ -322,7 +335,8 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../dts/overlays/pifi-mini-210-overlay.dts | 42 + arch/arm/boot/dts/overlays/piglow-overlay.dts | 97 + .../overlays/pineboards-hat-ai-overlay.dts | 18 + - .../boot/dts/overlays/piscreen-overlay.dts | 107 + + .../pineboards-hatdrive-poe-plus-overlay.dts | 19 + + .../boot/dts/overlays/piscreen-overlay.dts | 110 + .../boot/dts/overlays/piscreen2r-overlay.dts | 106 + .../arm/boot/dts/overlays/pisound-overlay.dts | 118 + .../boot/dts/overlays/pisound-pi5-overlay.dts | 31 + @@ -333,6 +347,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../boot/dts/overlays/pps-gpio-overlay.dts | 39 + .../boot/dts/overlays/proto-codec-overlay.dts | 39 + .../boot/dts/overlays/pwm-2chan-overlay.dts | 48 + + .../boot/dts/overlays/pwm-gpio-overlay.dts | 38 + .../boot/dts/overlays/pwm-ir-tx-overlay.dts | 40 + arch/arm/boot/dts/overlays/pwm-overlay.dts | 44 + arch/arm/boot/dts/overlays/pwm1-overlay.dts | 59 + @@ -349,8 +364,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../boot/dts/overlays/rpi-ft5406-overlay.dts | 25 + .../arm/boot/dts/overlays/rpi-poe-overlay.dts | 154 + .../dts/overlays/rpi-poe-plus-overlay.dts | 49 + - .../boot/dts/overlays/rpi-sense-overlay.dts | 47 + - .../dts/overlays/rpi-sense-v2-overlay.dts | 47 + + .../dts/overlays/rpi-rp2040-gpio-bridge.dtsi | 21 + + .../boot/dts/overlays/rpi-sense-overlay.dts | 69 + + .../dts/overlays/rpi-sense-v2-overlay.dts | 69 + arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 34 + .../rra-digidac1-wm8741-audio-overlay.dts | 49 + .../boot/dts/overlays/sainsmart18-overlay.dts | 52 + @@ -399,7 +415,8 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../boot/dts/overlays/ssd1306-spi-overlay.dts | 85 + .../boot/dts/overlays/ssd1331-spi-overlay.dts | 83 + .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 + - .../overlays/sunfounder-pironman5-overlay.dts | 51 + + .../overlays/sunfounder-pipower3-overlay.dts | 44 + + .../overlays/sunfounder-pironman5-overlay.dts | 55 + .../dts/overlays/superaudioboard-overlay.dts | 73 + arch/arm/boot/dts/overlays/sx150x-overlay.dts | 1706 ++++ .../dts/overlays/tc358743-audio-overlay.dts | 52 + @@ -424,7 +441,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../dts/overlays/upstream-pi4-overlay.dts | 137 + .../dts/overlays/vc4-fkms-v3d-overlay.dts | 46 + .../dts/overlays/vc4-fkms-v3d-pi4-overlay.dts | 50 + - .../overlays/vc4-kms-dpi-generic-overlay.dts | 81 + + .../overlays/vc4-kms-dpi-generic-overlay.dts | 82 + .../dts/overlays/vc4-kms-dpi-hyperpixel.dtsi | 94 + .../vc4-kms-dpi-hyperpixel2r-overlay.dts | 114 + .../vc4-kms-dpi-hyperpixel4-overlay.dts | 57 + @@ -437,7 +454,8 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../vc4-kms-dsi-ili9881-7inch-overlay.dts | 122 + .../vc4-kms-dsi-lt070me05000-overlay.dts | 69 + .../vc4-kms-dsi-lt070me05000-v2-overlay.dts | 64 + - .../vc4-kms-dsi-waveshare-panel-overlay.dts | 126 + + .../vc4-kms-dsi-waveshare-800x480-overlay.dts | 119 + + .../vc4-kms-dsi-waveshare-panel-overlay.dts | 133 + .../overlays/vc4-kms-kippah-7inch-overlay.dts | 26 + .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 124 + .../dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 200 + @@ -455,9 +473,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../waveshare-can-fd-hat-mode-b-overlay.dts | 103 + .../arm/boot/dts/overlays/wittypi-overlay.dts | 44 + .../dts/overlays/wm8960-soundcard-overlay.dts | 82 + - arch/arm/configs/bcm2709_defconfig | 1585 ++++ - arch/arm/configs/bcm2711_defconfig | 1615 ++++ - arch/arm/configs/bcmrpi_defconfig | 1578 ++++ + arch/arm/configs/bcm2709_defconfig | 1601 ++++ + arch/arm/configs/bcm2711_defconfig | 1633 ++++ + arch/arm/configs/bcmrpi_defconfig | 1594 ++++ arch/arm/include/asm/cacheflush.h | 21 + arch/arm/include/asm/glue-cache.h | 2 + arch/arm/include/asm/irqflags.h | 16 +- @@ -477,7 +495,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm/lib/memmove_rpi.S | 63 + arch/arm/lib/memset_rpi.S | 132 + arch/arm/lib/uaccess_with_memcpy.c | 125 +- - arch/arm/mach-bcm/Kconfig | 26 + + arch/arm/mach-bcm/Kconfig | 9 + arch/arm/mach-bcm/board_bcm2835.c | 109 + arch/arm/mm/cache-v6.S | 4 +- arch/arm/mm/cache-v7.S | 6 +- @@ -485,9 +503,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm/mm/proc-syms.c | 3 + arch/arm/mm/proc-v6.S | 15 +- arch/arm/vfp/vfpmodule.c | 25 +- - arch/arm64/Kconfig | 3 +- + arch/arm64/Kconfig | 13 +- arch/arm64/boot/dts/Makefile | 2 + - arch/arm64/boot/dts/broadcom/Makefile | 18 + + arch/arm64/boot/dts/broadcom/Makefile | 21 + .../boot/dts/broadcom/bcm2710-rpi-2-b.dts | 1 + .../dts/broadcom/bcm2710-rpi-3-b-plus.dts | 1 + .../boot/dts/broadcom/bcm2710-rpi-3-b.dts | 1 + @@ -496,16 +514,24 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../boot/dts/broadcom/bcm2710-rpi-zero-2.dts | 1 + .../boot/dts/broadcom/bcm2711-rpi-cm4.dts | 1 + .../boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 1 + - .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 2 + - .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 2 + - .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 2 + - .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 2 + - .../dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi | 1 + - .../dts/broadcom/bcm283x-rpi-lan7515.dtsi | 1 + + .../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 750 ++ + .../boot/dts/broadcom/bcm2712-rpi-500.dts | 142 + + .../boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi | 28 + + .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts | 5 + + .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts | 5 + + .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 754 ++ + .../boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi | 14 + + .../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts | 5 + + .../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts | 5 + + .../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi | 22 + + arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi | 466 ++ + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 1308 +++ + .../boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 107 + + arch/arm64/boot/dts/broadcom/rp1.dtsi | 1289 +++ arch/arm64/boot/dts/overlays | 1 + - arch/arm64/configs/bcm2711_defconfig | 1677 ++++ - arch/arm64/configs/bcm2712_defconfig | 1680 ++++ - arch/arm64/configs/bcmrpi3_defconfig | 1561 ++++ + arch/arm64/configs/bcm2711_defconfig | 1698 ++++ + arch/arm64/configs/bcm2712_defconfig | 1701 ++++ + arch/arm64/configs/bcmrpi3_defconfig | 1575 ++++ arch/arm64/crypto/aes-cipher-glue.c | 11 + arch/arm64/crypto/aes-glue.c | 4 +- arch/arm64/crypto/aes-neonbs-glue.c | 5 - @@ -513,6 +539,11 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) arch/arm64/kernel/cpuinfo.c | 23 + arch/arm64/kernel/process.c | 4 +- arch/arm64/kernel/setup.c | 4 +- + drivers/base/Kconfig | 7 + + drivers/base/Makefile | 1 + + drivers/base/arch_numa.c | 6 + + drivers/base/numa_emulation.c | 72 + + drivers/base/numa_emulation.h | 21 + drivers/bluetooth/btbcm.c | 9 +- drivers/bluetooth/hci_h5.c | 3 +- drivers/char/Kconfig | 10 + @@ -535,13 +566,13 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/clk/clk-hifiberry-dachd.c | 331 + drivers/clk/clk-hifiberry-dacpro.c | 181 + drivers/clk/clk-rp1-sdio.c | 600 ++ - drivers/clk/clk-rp1.c | 2422 ++++++ + drivers/clk/clk-rp1.c | 2500 ++++++ + drivers/dma-buf/heaps/system_heap.c | 10 +- drivers/dma/Kconfig | 4 + drivers/dma/Makefile | 1 + drivers/dma/bcm2708-dmaengine.c | 281 + drivers/dma/bcm2835-dma.c | 735 +- - .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 137 +- - drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + + .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 178 +- drivers/firmware/psci/psci.c | 9 +- drivers/firmware/raspberrypi.c | 149 +- drivers/gpio/Kconfig | 25 +- @@ -552,54 +583,54 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/gpio/gpio-mmio.c | 124 +- drivers/gpio/gpio-pca953x.c | 1 + drivers/gpio/gpio-pwm.c | 144 + - drivers/gpio/gpiolib.c | 10 +- + drivers/gpio/gpiolib.c | 23 +- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/bridge/Kconfig | 1 + + drivers/gpu/drm/bridge/panel.c | 6 + drivers/gpu/drm/bridge/tc358762.c | 26 +- drivers/gpu/drm/drm_atomic_helper.c | 18 +- drivers/gpu/drm/drm_atomic_state_helper.c | 14 + drivers/gpu/drm/drm_atomic_uapi.c | 19 + + drivers/gpu/drm/drm_bridge.c | 14 + drivers/gpu/drm/drm_color_mgmt.c | 40 +- drivers/gpu/drm/drm_connector.c | 77 +- drivers/gpu/drm/drm_fb_helper.c | 11 +- drivers/gpu/drm/drm_modes.c | 5 +- drivers/gpu/drm/drm_probe_helper.c | 5 +- - .../gpu/drm/i915/display/intel_backlight.c | 6 +- drivers/gpu/drm/i915/display/intel_display.c | 13 + drivers/gpu/drm/msm/msm_atomic.c | 2 + drivers/gpu/drm/panel/Kconfig | 32 + drivers/gpu/drm/panel/Makefile | 3 + drivers/gpu/drm/panel/panel-ilitek-ili9806e.c | 484 ++ - drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 955 ++- + drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 979 ++- .../gpu/drm/panel/panel-jdi-lt070me05000.c | 19 +- .../drm/panel/panel-raspberrypi-touchscreen.c | 44 +- drivers/gpu/drm/panel/panel-simple.c | 238 +- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 407 +- drivers/gpu/drm/panel/panel-tdo-y17p.c | 277 + - drivers/gpu/drm/panel/panel-waveshare-dsi.c | 434 + + drivers/gpu/drm/panel/panel-waveshare-dsi.c | 488 ++ drivers/gpu/drm/rp1/Kconfig | 5 + drivers/gpu/drm/rp1/Makefile | 4 + drivers/gpu/drm/rp1/rp1-dpi/Kconfig | 11 + drivers/gpu/drm/rp1/rp1-dpi/Makefile | 5 + - drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 415 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 417 + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 69 + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_cfg.c | 510 ++ - drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 492 ++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 504 ++ drivers/gpu/drm/rp1/rp1-dsi/Kconfig | 14 + drivers/gpu/drm/rp1/rp1-dsi/Makefile | 5 + - drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 535 ++ - drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 94 + - drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 443 + - drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1513 ++++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 541 ++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 96 + + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 455 ++ + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1599 ++++ drivers/gpu/drm/rp1/rp1-vec/Kconfig | 11 + drivers/gpu/drm/rp1/rp1-vec/Makefile | 5 + - drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 602 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c | 604 ++ drivers/gpu/drm/rp1/rp1-vec/rp1_vec.h | 72 + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_cfg.c | 508 ++ - drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 568 ++ + drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 580 ++ drivers/gpu/drm/rp1/rp1-vec/vec_regs.h | 1420 ++++ - drivers/gpu/drm/solomon/ssd130x.c | 2 +- drivers/gpu/drm/tiny/ili9486.c | 1 - drivers/gpu/drm/v3d/v3d_bo.c | 12 +- drivers/gpu/drm/v3d/v3d_debugfs.c | 258 +- @@ -615,29 +646,30 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/gpu/drm/vc4/tests/vc4_mock.h | 28 +- drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 13 +- drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 32 +- - drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 308 + + drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c | 314 + .../gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 225 +- drivers/gpu/drm/vc4/vc4_bo.c | 28 +- - drivers/gpu/drm/vc4/vc4_crtc.c | 197 +- + drivers/gpu/drm/vc4/vc4_crtc.c | 214 +- drivers/gpu/drm/vc4/vc4_debugfs.c | 3 +- + drivers/gpu/drm/vc4/vc4_dpi.c | 22 + drivers/gpu/drm/vc4/vc4_drv.c | 90 +- - drivers/gpu/drm/vc4/vc4_drv.h | 144 +- - drivers/gpu/drm/vc4/vc4_dsi.c | 98 +- + drivers/gpu/drm/vc4/vc4_drv.h | 172 +- + drivers/gpu/drm/vc4/vc4_dsi.c | 151 +- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2077 +++++ drivers/gpu/drm/vc4/vc4_gem.c | 24 +- - drivers/gpu/drm/vc4/vc4_hdmi.c | 216 +- - drivers/gpu/drm/vc4/vc4_hdmi.h | 31 + - drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 640 ++ + drivers/gpu/drm/vc4/vc4_hdmi.c | 301 +- + drivers/gpu/drm/vc4/vc4_hdmi.h | 43 + + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 647 ++ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 222 +- - drivers/gpu/drm/vc4/vc4_hvs.c | 1878 ++++- + drivers/gpu/drm/vc4/vc4_hvs.c | 1867 ++++- drivers/gpu/drm/vc4/vc4_irq.c | 10 +- - drivers/gpu/drm/vc4/vc4_kms.c | 135 +- + drivers/gpu/drm/vc4/vc4_kms.c | 173 +- drivers/gpu/drm/vc4/vc4_perfmon.c | 20 +- - drivers/gpu/drm/vc4/vc4_plane.c | 1031 ++- + drivers/gpu/drm/vc4/vc4_plane.c | 1281 ++- drivers/gpu/drm/vc4/vc4_regs.h | 357 +- drivers/gpu/drm/vc4/vc4_render_cl.c | 2 +- drivers/gpu/drm/vc4/vc4_txp.c | 91 +- - drivers/gpu/drm/vc4/vc4_v3d.c | 10 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 12 +- drivers/gpu/drm/vc4/vc4_validate.c | 8 +- drivers/gpu/drm/vc4/vc4_validate_shaders.c | 2 +- drivers/gpu/drm/vc4/vc4_vec.c | 172 +- @@ -647,10 +679,11 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/hid/usbhid/hid-core.c | 7 +- drivers/hwmon/Kconfig | 7 + drivers/hwmon/Makefile | 1 + + drivers/hwmon/adt7410.c | 8 + drivers/hwmon/aht10.c | 7 + drivers/hwmon/ds1621.c | 10 + drivers/hwmon/emc2305.c | 95 +- - drivers/hwmon/pwm-fan.c | 67 +- + drivers/hwmon/pwm-fan.c | 59 +- drivers/hwmon/rp1-adc.c | 307 + drivers/hwmon/sht3x.c | 12 +- drivers/i2c/busses/Kconfig | 19 + @@ -658,20 +691,15 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/i2c/busses/i2c-bcm2708.c | 512 ++ drivers/i2c/busses/i2c-bcm2835.c | 133 +- drivers/i2c/busses/i2c-designware-common.c | 39 + - drivers/i2c/busses/i2c-designware-core.h | 11 + + drivers/i2c/busses/i2c-designware-core.h | 10 + drivers/i2c/busses/i2c-designware-master.c | 76 +- drivers/i2c/busses/i2c-gpio.c | 4 +- drivers/i2c/i2c-mux.c | 5 + drivers/iio/adc/mcp3422.c | 9 +- drivers/iio/light/tsl4531.c | 7 + drivers/iio/light/veml6070.c | 7 + - drivers/input/joystick/Kconfig | 8 + - drivers/input/joystick/Makefile | 1 + - drivers/input/joystick/rpisense-js.c | 153 + - drivers/input/misc/da7280.c | 4 +- - drivers/input/misc/pwm-beeper.c | 4 +- - drivers/input/misc/pwm-vibra.c | 8 +- - drivers/input/touchscreen/ads7846.c | 11 + + drivers/input/joystick/sensehat-joystick.c | 2 +- + drivers/input/keyboard/matrix_keypad.c | 48 +- drivers/input/touchscreen/edt-ft5x06.c | 124 +- drivers/input/touchscreen/goodix.c | 75 +- drivers/input/touchscreen/goodix.h | 5 + @@ -680,7 +708,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/iommu/bcm2712-iommu-cache.c | 77 + drivers/iommu/bcm2712-iommu.c | 665 ++ drivers/iommu/bcm2712-iommu.h | 45 + - drivers/iommu/iommu.c | 14 +- + drivers/iommu/iommu.c | 55 +- drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm2712-mip.c | 323 + @@ -688,16 +716,14 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/irqchip/irq-bcm2836.c | 28 +- drivers/irqchip/irq-brcmstb-l2.c | 17 + drivers/leds/leds-gpio.c | 17 +- - drivers/leds/leds-pwm.c | 2 +- - drivers/leds/rgb/leds-pwm-multicolor.c | 4 +- drivers/leds/trigger/Kconfig | 18 + drivers/leds/trigger/Makefile | 2 + drivers/leds/trigger/ledtrig-actpwr.c | 190 + drivers/leds/trigger/ledtrig-input.c | 55 + drivers/mailbox/bcm2835-mailbox.c | 18 +- .../media/common/videobuf2/videobuf2-core.c | 21 +- - drivers/media/i2c/Kconfig | 115 + - drivers/media/i2c/Makefile | 10 + + drivers/media/i2c/Kconfig | 127 + + drivers/media/i2c/Makefile | 11 + drivers/media/i2c/ad5398_vcm.c | 340 + drivers/media/i2c/adv7180.c | 88 +- drivers/media/i2c/arducam-pivariety.c | 1472 ++++ @@ -709,17 +735,58 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/media/i2c/imx258.c | 799 +- drivers/media/i2c/imx296.c | 166 +- drivers/media/i2c/imx477.c | 2339 ++++++ + drivers/media/i2c/imx500.c | 3227 ++++++++ drivers/media/i2c/imx519.c | 2146 +++++ drivers/media/i2c/imx708.c | 2116 +++++ drivers/media/i2c/irs1125.c | 1197 +++ drivers/media/i2c/irs1125.h | 95 + drivers/media/i2c/ov2311.c | 1178 +++ - drivers/media/i2c/ov5647.c | 158 +- + drivers/media/i2c/ov5647.c | 465 +- drivers/media/i2c/ov64a40.c | 3686 +++++++++ drivers/media/i2c/ov7251.c | 62 +- drivers/media/i2c/ov9282.c | 8 +- drivers/media/i2c/tc358743.c | 121 +- drivers/media/mc/mc-request.c | 35 + + drivers/media/pci/Kconfig | 1 + + drivers/media/pci/Makefile | 3 +- + drivers/media/pci/hailo/Kconfig | 6 + + drivers/media/pci/hailo/Makefile | 34 + + drivers/media/pci/hailo/common/fw_operation.c | 103 + + drivers/media/pci/hailo/common/fw_operation.h | 25 + + .../media/pci/hailo/common/fw_validation.c | 114 + + .../media/pci/hailo/common/fw_validation.h | 65 + + .../pci/hailo/common/hailo_ioctl_common.h | 669 ++ + .../pci/hailo/common/hailo_pcie_version.h | 13 + + .../media/pci/hailo/common/hailo_resource.c | 128 + + .../media/pci/hailo/common/hailo_resource.h | 39 + + drivers/media/pci/hailo/common/pcie_common.c | 872 ++ + drivers/media/pci/hailo/common/pcie_common.h | 168 + + drivers/media/pci/hailo/common/utils.h | 61 + + drivers/media/pci/hailo/common/vdma_common.c | 877 ++ + drivers/media/pci/hailo/common/vdma_common.h | 257 + + .../pci/hailo/include/hailo_pcie_version.h | 14 + + drivers/media/pci/hailo/src/fops.c | 762 ++ + drivers/media/pci/hailo/src/fops.h | 22 + + drivers/media/pci/hailo/src/pci_soc_ioctl.c | 155 + + drivers/media/pci/hailo/src/pci_soc_ioctl.h | 19 + + drivers/media/pci/hailo/src/pcie.c | 1095 +++ + drivers/media/pci/hailo/src/pcie.h | 84 + + drivers/media/pci/hailo/src/sysfs.c | 45 + + drivers/media/pci/hailo/src/sysfs.h | 13 + + drivers/media/pci/hailo/src/utils.c | 26 + + drivers/media/pci/hailo/src/utils.h | 21 + + drivers/media/pci/hailo/utils/compact.h | 153 + + drivers/media/pci/hailo/utils/fw_common.h | 19 + + .../pci/hailo/utils/integrated_nnc_utils.c | 101 + + .../pci/hailo/utils/integrated_nnc_utils.h | 30 + + drivers/media/pci/hailo/utils/logs.c | 8 + + drivers/media/pci/hailo/utils/logs.h | 45 + + drivers/media/pci/hailo/vdma/ioctl.c | 715 ++ + drivers/media/pci/hailo/vdma/ioctl.h | 37 + + drivers/media/pci/hailo/vdma/memory.c | 661 ++ + drivers/media/pci/hailo/vdma/memory.h | 54 + + drivers/media/pci/hailo/vdma/vdma.c | 302 + + drivers/media/pci/hailo/vdma/vdma.h | 161 + drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 2 + drivers/media/platform/bcm2835/Kconfig | 21 + @@ -730,8 +797,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/media/platform/raspberrypi/Makefile | 4 + .../platform/raspberrypi/pisp_be/Kconfig | 12 + .../platform/raspberrypi/pisp_be/Makefile | 6 + - .../platform/raspberrypi/pisp_be/pisp_be.c | 1993 +++++ - .../raspberrypi/pisp_be/pisp_be_config.h | 533 ++ + .../platform/raspberrypi/pisp_be/pisp_be.c | 1866 +++++ .../raspberrypi/pisp_be/pisp_be_formats.h | 519 ++ .../platform/raspberrypi/rp1_cfe/Kconfig | 14 + .../platform/raspberrypi/rp1_cfe/Makefile | 6 + @@ -748,30 +814,32 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../raspberrypi/rp1_cfe/pisp_fe_config.h | 272 + .../raspberrypi/rp1_cfe/pisp_statistics.h | 62 + .../platform/raspberrypi/rp1_cfe/pisp_types.h | 144 + - drivers/media/platform/video-mux.c | 73 +- + drivers/media/platform/video-mux.c | 86 +- drivers/media/rc/Kconfig | 1 + - drivers/media/rc/pwm-ir-tx.c | 87 +- + drivers/media/rc/pwm-ir-tx.c | 83 +- drivers/media/spi/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 + + drivers/media/v4l2-core/v4l2-common.c | 2 + drivers/media/v4l2-core/v4l2-ctrls-defs.c | 1 + drivers/media/v4l2-core/v4l2-ioctl.c | 22 + drivers/media/v4l2-core/v4l2-mem2mem.c | 9 +- - drivers/mfd/Kconfig | 29 + - drivers/mfd/Makefile | 3 + + drivers/mfd/Kconfig | 21 + + drivers/mfd/Makefile | 2 + drivers/mfd/bcm2835-pm.c | 28 +- drivers/mfd/rp1.c | 376 + - drivers/mfd/rpisense-core.c | 163 + - drivers/mfd/simple-mfd-i2c.c | 10 + + drivers/mfd/simple-mfd-i2c.c | 11 + drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/bcm2835_smi.c | 953 +++ - drivers/mmc/core/block.c | 59 +- + drivers/mmc/core/block.c | 92 +- drivers/mmc/core/bus.c | 2 + drivers/mmc/core/card.h | 1 + - drivers/mmc/core/core.c | 10 +- - drivers/mmc/core/mmc.c | 4 +- - drivers/mmc/core/quirks.h | 38 +- - drivers/mmc/core/sd.c | 203 +- + drivers/mmc/core/core.c | 20 +- + drivers/mmc/core/mmc.c | 6 +- + drivers/mmc/core/queue.c | 9 + + drivers/mmc/core/queue.h | 1 + + drivers/mmc/core/quirks.h | 37 + + drivers/mmc/core/sd.c | 209 +- drivers/mmc/core/sd_ops.c | 134 + drivers/mmc/core/sd_ops.h | 6 + drivers/mmc/host/Kconfig | 41 + @@ -779,15 +847,15 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/mmc/host/bcm2835-mmc.c | 1562 ++++ drivers/mmc/host/bcm2835-sdhost.c | 2220 +++++ drivers/mmc/host/bcm2835.c | 17 +- - drivers/mmc/host/cqhci-core.c | 13 +- - drivers/mmc/host/sdhci-brcmstb.c | 282 +- + drivers/mmc/host/cqhci-core.c | 11 +- + drivers/mmc/host/sdhci-brcmstb.c | 311 +- drivers/mmc/host/sdhci-iproc.c | 1 + drivers/mmc/host/sdhci-of-dwcmshc.c | 59 +- drivers/mmc/host/sdhci-pltfm.c | 8 + drivers/mmc/host/sdhci-pltfm.h | 3 + - drivers/mmc/host/sdhci.c | 36 +- + drivers/mmc/host/sdhci.c | 51 +- drivers/mmc/host/sdhci.h | 9 + - .../net/ethernet/broadcom/genet/bcmgenet.c | 45 +- + .../net/ethernet/broadcom/genet/bcmgenet.c | 29 +- .../net/ethernet/broadcom/genet/bcmgenet.h | 2 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 +- drivers/net/ethernet/cadence/macb.h | 25 + @@ -800,14 +868,14 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/net/phy/broadcom.c | 48 +- drivers/net/phy/microchip.c | 27 + drivers/net/usb/lan78xx.c | 64 +- - drivers/net/usb/smsc95xx.c | 51 +- + drivers/net/usb/smsc95xx.c | 41 +- .../broadcom/brcm80211/brcmfmac/bus.h | 2 +- - .../broadcom/brcm80211/brcmfmac/cfg80211.c | 364 +- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 370 +- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 18 + .../broadcom/brcm80211/brcmfmac/common.c | 39 + .../broadcom/brcm80211/brcmfmac/core.c | 13 +- .../broadcom/brcm80211/brcmfmac/debug.h | 8 +- - .../broadcom/brcm80211/brcmfmac/feature.c | 1 + + .../broadcom/brcm80211/brcmfmac/feature.c | 11 +- .../broadcom/brcm80211/brcmfmac/feature.h | 2 + .../broadcom/brcm80211/brcmfmac/firmware.c | 21 +- .../broadcom/brcm80211/brcmfmac/fweh.c | 28 +- @@ -815,7 +883,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../broadcom/brcm80211/brcmfmac/fwil_types.h | 45 + .../broadcom/brcm80211/brcmfmac/p2p.c | 5 + .../broadcom/brcm80211/brcmfmac/pcie.c | 2 +- - .../broadcom/brcm80211/brcmfmac/sdio.c | 262 +- + .../broadcom/brcm80211/brcmfmac/sdio.c | 263 +- .../broadcom/brcm80211/brcmfmac/sdio.h | 110 + .../broadcom/brcm80211/brcmfmac/usb.c | 4 +- .../broadcom/brcm80211/include/chipcommon.h | 2 + @@ -826,7 +894,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/of/Makefile | 1 + drivers/of/configfs.c | 277 + drivers/of/overlay.c | 2 + - drivers/pci/controller/pcie-brcmstb.c | 533 +- + drivers/pci/controller/pcie-brcmstb.c | 545 +- drivers/perf/Kconfig | 8 + drivers/perf/Makefile | 1 + drivers/perf/raspberrypi_axi_monitor.c | 830 ++ @@ -840,8 +908,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/pinctrl/bcm/Makefile | 1 + drivers/pinctrl/bcm/pinctrl-bcm2712.c | 1247 +++ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 44 +- - drivers/pinctrl/pinctrl-rp1.c | 1605 ++++ - drivers/platform/x86/lenovo-yogabook.c | 2 +- + drivers/pinctrl/pinctrl-rp1.c | 1695 ++++ drivers/pmdomain/bcm/bcm2835-power.c | 29 +- drivers/power/reset/gpio-poweroff.c | 21 +- drivers/power/supply/Kconfig | 7 + @@ -849,36 +916,37 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/power/supply/rpi_poe_power.c | 243 + drivers/pps/clients/pps-gpio.c | 3 + drivers/pps/pps.c | 6 +- - drivers/pwm/Kconfig | 9 + - drivers/pwm/Makefile | 1 + - drivers/pwm/core.c | 74 +- + drivers/pwm/Kconfig | 20 + + drivers/pwm/Makefile | 2 + + drivers/pwm/core.c | 62 +- drivers/pwm/pwm-bcm2835.c | 59 +- + drivers/pwm/pwm-gpio.c | 240 + drivers/pwm/pwm-raspberrypi-poe.c | 81 +- drivers/pwm/pwm-renesas-tpu.c | 1 - drivers/pwm/pwm-rp1.c | 203 + - drivers/pwm/pwm-twl-led.c | 2 +- - drivers/pwm/pwm-vt8500.c | 2 +- - drivers/pwm/sysfs.c | 10 +- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + - drivers/regulator/pwm-regulator.c | 4 +- - .../regulator/rpi-panel-attiny-regulator.c | 27 +- - drivers/regulator/rpi-panel-v2-regulator.c | 189 + + .../regulator/rpi-panel-attiny-regulator.c | 77 +- + drivers/regulator/rpi-panel-v2-regulator.c | 240 + drivers/reset/Kconfig | 2 +- drivers/reset/reset-brcmstb-rescal.c | 10 + drivers/rtc/Kconfig | 11 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-ds3232.c | 7 + drivers/rtc/rtc-pcf2123.c | 1 + - drivers/rtc/rtc-pcf8523.c | 28 + + drivers/rtc/rtc-pcf8523.c | 30 +- drivers/rtc/rtc-rpi.c | 277 + drivers/rtc/rtc-rv3028.c | 24 +- drivers/soc/bcm/Kconfig | 1 + + drivers/spi/Kconfig | 12 + + drivers/spi/Makefile | 1 + drivers/spi/spi-bcm2835.c | 37 +- - drivers/spi/spi-dw-core.c | 12 +- - drivers/spi/spi-dw-dma.c | 6 +- + drivers/spi/spi-dw-core.c | 132 +- + drivers/spi/spi-dw-dma.c | 43 +- drivers/spi/spi-dw-mmio.c | 8 +- + drivers/spi/spi-dw.h | 3 + drivers/spi/spi-gpio.c | 105 +- + drivers/spi/spi-rp2040-gpio-bridge.c | 1244 +++ drivers/spi/spi.c | 9 + drivers/spi/spidev.c | 8 +- drivers/staging/fbtft/fb_st7735r.c | 38 +- @@ -893,11 +961,11 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/staging/media/rpivid/rpivid.h | 203 + drivers/staging/media/rpivid/rpivid_dec.c | 96 + drivers/staging/media/rpivid/rpivid_dec.h | 19 + - drivers/staging/media/rpivid/rpivid_h265.c | 2706 +++++++ + drivers/staging/media/rpivid/rpivid_h265.c | 2712 +++++++ drivers/staging/media/rpivid/rpivid_hw.c | 383 + drivers/staging/media/rpivid/rpivid_hw.h | 303 + - drivers/staging/media/rpivid/rpivid_video.c | 696 ++ - drivers/staging/media/rpivid/rpivid_video.h | 33 + + drivers/staging/media/rpivid/rpivid_video.c | 691 ++ + drivers/staging/media/rpivid/rpivid_video.h | 38 + drivers/staging/vc04_services/Kconfig | 4 + drivers/staging/vc04_services/Makefile | 3 + .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 3 +- @@ -909,12 +977,12 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) .../vc04_services/bcm2835-codec/Kconfig | 11 + .../vc04_services/bcm2835-codec/Makefile | 8 + .../staging/vc04_services/bcm2835-codec/TODO | 1 + - .../bcm2835-codec/bcm2835-v4l2-codec.c | 3964 +++++++++ + .../bcm2835-codec/bcm2835-v4l2-codec.c | 4019 +++++++++ .../staging/vc04_services/bcm2835-isp/Kconfig | 14 + .../vc04_services/bcm2835-isp/Makefile | 8 + .../bcm2835-isp/bcm2835-isp-ctrls.h | 72 + .../bcm2835-isp/bcm2835-isp-fmts.h | 558 ++ - .../bcm2835-isp/bcm2835-v4l2-isp.c | 1816 +++++ + .../bcm2835-isp/bcm2835-v4l2-isp.c | 1833 +++++ .../include/linux/broadcom/vc_sm_cma_ioctl.h | 114 + .../interface/vchiq_arm/vchiq_arm.c | 179 +- .../staging/vc04_services/vc-sm-cma/Kconfig | 10 + @@ -940,7 +1008,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/tty/serial/8250/8250_bcm2835aux.c | 8 + drivers/tty/serial/8250/8250_core.c | 15 + drivers/tty/serial/8250/8250_port.c | 9 + - drivers/tty/serial/amba-pl011.c | 108 + + drivers/tty/serial/amba-pl011.c | 115 + drivers/tty/serial/sc16is7xx.c | 5 + drivers/usb/Makefile | 1 + drivers/usb/core/generic.c | 1 + @@ -952,7 +1020,6 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/usb/dwc3/core.h | 17 +- drivers/usb/dwc3/host.c | 9 +- drivers/usb/gadget/file_storage.c | 3676 +++++++++ - drivers/usb/gadget/function/uvc_configfs.c | 4 +- drivers/usb/host/Kconfig | 10 + drivers/usb/host/Makefile | 1 + drivers/usb/host/dwc_common_port/Makefile | 58 + @@ -995,9 +1062,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1772 ++++ drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1433 ++++ - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 399 + + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 395 + drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 80 + - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4366 ++++++++++ + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4364 ++++++++++ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 870 ++ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1135 +++ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 421 + @@ -1023,9 +1090,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/usb/phy/phy-generic.c | 7 - drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + - drivers/video/backlight/lm3630a_bl.c | 2 +- - drivers/video/backlight/lp855x_bl.c | 2 +- - drivers/video/backlight/pwm_bl.c | 12 +- + drivers/video/backlight/backlight.c | 21 + drivers/video/backlight/rpi_backlight.c | 119 + drivers/video/fbdev/Kconfig | 28 + drivers/video/fbdev/Makefile | 2 + @@ -1033,36 +1098,37 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) drivers/video/fbdev/core/fb_chrdev.c | 35 + drivers/video/fbdev/core/fb_defio.c | 3 +- drivers/video/fbdev/core/fbmem.c | 19 +- - drivers/video/fbdev/rpisense-fb.c | 297 + - drivers/video/fbdev/ssd1307fb.c | 2 +- + drivers/video/fbdev/rpisense-fb.c | 296 + drivers/video/logo/logo_linux_clut224.ppm | 2483 ++---- drivers/w1/masters/w1-gpio.c | 15 +- drivers/w1/w1.c | 2 + drivers/w1/w1_io.c | 37 +- drivers/watchdog/bcm2835_wdt.c | 51 +- + fs/ntfs3/fslog.c | 2 + include/drm/drm_color_mgmt.h | 3 + include/drm/drm_connector.h | 7 + include/drm/drm_mipi_dsi.h | 38 +- include/drm/drm_plane.h | 37 + - include/dt-bindings/clock/rp1.h | 56 + + include/dt-bindings/clock/rp1.h | 60 + include/dt-bindings/gpio/gpio-fsm.h | 21 + include/dt-bindings/mfd/rp1.h | 235 + + include/linux/backlight.h | 15 + include/linux/brcmphy.h | 1 + include/linux/broadcom/bcm2835_smi.h | 391 + include/linux/broadcom/vc_mem.h | 39 + + include/linux/cma.h | 9 + include/linux/fb.h | 2 + include/linux/gpio/driver.h | 1 + - include/linux/iommu.h | 8 +- + include/linux/iommu.h | 6 +- include/linux/leds.h | 3 + - include/linux/mfd/rpisense/core.h | 47 + - include/linux/mfd/rpisense/framebuffer.h | 32 + + include/linux/mfd/rpisense/framebuffer.h | 35 + include/linux/mfd/rpisense/joystick.h | 35 + include/linux/microchipphy.h | 8 + - include/linux/mmc/card.h | 2 + + include/linux/mmc/card.h | 3 + include/linux/mmc/sd.h | 12 + include/linux/module.h | 2 +- include/linux/platform_data/dma-bcm2708.h | 143 + - include/linux/pwm.h | 57 +- + include/linux/pwm.h | 29 +- include/linux/rp1_platform.h | 20 + include/linux/usb.h | 2 + include/linux/usb/hcd.h | 7 + @@ -1076,18 +1142,24 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) include/uapi/linux/bcm2835-isp.h | 347 + include/uapi/linux/fb.h | 12 + include/uapi/linux/media-bus-format.h | 3 + - include/uapi/linux/v4l2-controls.h | 5 + - include/uapi/linux/videodev2.h | 40 + - kernel/cgroup/cgroup.c | 38 + + .../linux/media/raspberrypi/pisp_be_config.h | 968 +++ + .../linux/media/raspberrypi/pisp_common.h | 202 + + include/uapi/linux/v4l2-controls.h | 11 + + include/uapi/linux/videodev2.h | 42 + + kernel/cgroup/cgroup.c | 25 + kernel/resource.c | 6 + + lib/earlycpio.c | 1 + + mm/cma.c | 36 + + mm/mempolicy.c | 49 +- mm/page_alloc.c | 28 +- - net/bluetooth/hci_sync.c | 4 +- + mm/vmscan.c | 2 +- + net/bluetooth/hci_sync.c | 5 +- net/bluetooth/smp.c | 16 +- net/wireless/certs/debian.hex | 1426 ++++ scripts/Makefile.dtbinst | 5 +- scripts/Makefile.lib | 19 + - sound/soc/bcm/Kconfig | 269 + - sound/soc/bcm/Makefile | 71 +- + sound/soc/bcm/Kconfig | 284 + + sound/soc/bcm/Makefile | 73 +- sound/soc/bcm/allo-boss-dac.c | 471 ++ sound/soc/bcm/allo-boss2-dac.c | 1130 +++ sound/soc/bcm/allo-katana-codec.c | 386 + @@ -1097,21 +1169,23 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) sound/soc/bcm/audioinjector-octo-soundcard.c | 347 + sound/soc/bcm/audioinjector-pi-soundcard.c | 190 + sound/soc/bcm/audiosense-pi.c | 248 + - sound/soc/bcm/bcm2835-i2s.c | 18 +- + sound/soc/bcm/bcm2835-i2s.c | 26 +- sound/soc/bcm/chipdip-dac.c | 275 + sound/soc/bcm/dacberry400.c | 259 + sound/soc/bcm/digidac1-soundcard.c | 421 + sound/soc/bcm/dionaudio_loco-v2.c | 118 + sound/soc/bcm/dionaudio_loco.c | 121 + sound/soc/bcm/fe-pi-audio.c | 154 + - sound/soc/bcm/googlevoicehat-codec.c | 214 + + sound/soc/bcm/googlevoicehat-codec.c | 213 + + sound/soc/bcm/hifiberry_adc.c | 174 + + sound/soc/bcm/hifiberry_adc_controls.h | 128 + sound/soc/bcm/hifiberry_dacplus.c | 563 ++ sound/soc/bcm/hifiberry_dacplusadc.c | 399 + - sound/soc/bcm/hifiberry_dacplusadcpro.c | 606 ++ + sound/soc/bcm/hifiberry_dacplusadcpro.c | 498 ++ sound/soc/bcm/hifiberry_dacplusdsp.c | 90 + sound/soc/bcm/hifiberry_dacplushd.c | 238 + sound/soc/bcm/i-sabre-q2m.c | 160 + - sound/soc/bcm/iqaudio-codec.c | 278 + + sound/soc/bcm/iqaudio-codec.c | 284 + sound/soc/bcm/iqaudio-dac.c | 224 + sound/soc/bcm/justboom-both.c | 267 + sound/soc/bcm/justboom-dac.c | 147 + @@ -1119,13 +1193,15 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) sound/soc/bcm/pisound.c | 1255 +++ sound/soc/bcm/rpi-cirrus.c | 1027 +++ sound/soc/bcm/rpi-proto.c | 147 + - sound/soc/bcm/rpi-simple-soundcard.c | 523 ++ + sound/soc/bcm/rpi-simple-soundcard.c | 560 ++ sound/soc/bcm/rpi-wm8804-soundcard.c | 549 ++ sound/soc/codecs/Kconfig | 26 +- sound/soc/codecs/Makefile | 8 + sound/soc/codecs/adau1977-i2c.c | 10 + sound/soc/codecs/cs42xx8-i2c.c | 9 +- sound/soc/codecs/cs42xx8.c | 10 + + sound/soc/codecs/da7213.c | 21 + + sound/soc/codecs/da7213.h | 1 + sound/soc/codecs/i-sabre-codec.c | 389 + sound/soc/codecs/i-sabre-codec.h | 42 + sound/soc/codecs/ma120x0p.c | 1380 ++++ @@ -1134,13 +1210,15 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) sound/soc/codecs/pcm512x.c | 38 +- sound/soc/codecs/tas5713.c | 360 + sound/soc/codecs/tas5713.h | 210 + - sound/soc/dwc/dwc-i2s.c | 169 +- - sound/soc/dwc/local.h | 12 + + sound/soc/dwc/dwc-i2s.c | 190 +- + sound/soc/dwc/local.h | 13 + sound/soc/soc-core.c | 14 +- sound/usb/card.c | 8 +- sound/usb/quirks.c | 2 + - 1135 files changed, 230272 insertions(+), 4326 deletions(-) + 1211 files changed, 246815 insertions(+), 4651 deletions(-) create mode 100644 Documentation/admin-guide/media/bcm2835-isp.rst + create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.dot + create mode 100644 Documentation/admin-guide/media/raspberrypi-pisp-be.rst create mode 100644 Documentation/devicetree/bindings/display/panel/panel-dsi.yaml create mode 100644 Documentation/devicetree/bindings/hwmon/microchip,emc2305.yaml create mode 100644 Documentation/devicetree/bindings/media/bcm2835-unicam.txt @@ -1154,7 +1232,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/rohm,bu64754.yaml rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (90%) + create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml + create mode 100644 Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml create mode 100644 Documentation/devicetree/bindings/media/rpivid_hevc.yaml create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi-dev.txt create mode 100644 Documentation/devicetree/bindings/misc/brcm,bcm2835-smi.txt @@ -1162,11 +1242,14 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt create mode 100644 Documentation/devicetree/bindings/pwm/pwm-rp1.yaml create mode 100644 Documentation/devicetree/bindings/rtc/rtc-rpi.txt + create mode 100644 Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml create mode 100644 Documentation/devicetree/bindings/vendor-prefixes.txt create mode 100644 Documentation/devicetree/configfs-overlays.txt + create mode 100644 Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-sensor-data.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst + create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y12p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y14p.rst create mode 100644 README.md @@ -1196,20 +1279,12 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts create mode 100644 arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712.dtsi - create mode 100644 arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts create mode 100644 arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi0-2lane.dtsi create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-csi1-4lane.dtsi create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_28.dtsi create mode 100644 arch/arm/boot/dts/broadcom/bcm283x-rpi-i2c0mux_0_44.dtsi - create mode 100644 arch/arm/boot/dts/broadcom/rp1.dtsi create mode 100644 arch/arm/boot/dts/overlays/Makefile create mode 100644 arch/arm/boot/dts/overlays/README create mode 100644 arch/arm/boot/dts/overlays/act-led-overlay.dts @@ -1294,8 +1369,11 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hat_map.dts + create mode 100644 arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp100-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/hifiberry-amp3-overlay.dts @@ -1338,6 +1416,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/i2c6-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2s-dac-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ilitek251x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx219-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx219.dtsi @@ -1353,6 +1432,9 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/imx477-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi create mode 100644 arch/arm/boot/dts/overlays/imx477_378.dtsi + create mode 100644 arch/arm/boot/dts/overlays/imx500-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx500.dtsi create mode 100644 arch/arm/boot/dts/overlays/imx519-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/imx519.dtsi create mode 100644 arch/arm/boot/dts/overlays/imx708-overlay.dts @@ -1417,6 +1499,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/pcf857x-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pcie-32bit-dma-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pcie-32bit-dma-pi5-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pibell-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pifacedigital-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pifi-40-overlay.dts @@ -1425,6 +1508,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/pifi-mini-210-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/piglow-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pineboards-hat-ai-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/piscreen-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/piscreen2r-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pisound-overlay.dts @@ -1436,6 +1520,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/pps-gpio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/proto-codec-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/pwm-gpio-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/pwm1-overlay.dts @@ -1452,6 +1537,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-poe-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/rpi-tv-overlay.dts @@ -1502,6 +1588,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ssd1331-spi-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/sunfounder-pipower3-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts create mode 100755 arch/arm/boot/dts/overlays/superaudioboard-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/sx150x-overlay.dts @@ -1540,6 +1627,7 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-ili9881-7inch-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-lt070me05000-v2-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts @@ -1577,15 +1665,25 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-cm4s.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712.dtsi create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts - create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi - create mode 120000 arch/arm64/boot/dts/broadcom/bcm283x-rpi-lan7515.dtsi + create mode 100644 arch/arm64/boot/dts/broadcom/rp1.dtsi create mode 120000 arch/arm64/boot/dts/overlays create mode 100644 arch/arm64/configs/bcm2711_defconfig create mode 100644 arch/arm64/configs/bcm2712_defconfig create mode 100644 arch/arm64/configs/bcmrpi3_defconfig + create mode 100644 drivers/base/numa_emulation.c + create mode 100644 drivers/base/numa_emulation.h create mode 100644 drivers/char/broadcom/Kconfig create mode 100644 drivers/char/broadcom/Makefile create mode 100644 drivers/char/broadcom/bcm2835_smi_dev.c @@ -1629,7 +1727,6 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h create mode 100644 drivers/hwmon/rp1-adc.c create mode 100644 drivers/i2c/busses/i2c-bcm2708.c - create mode 100644 drivers/input/joystick/rpisense-js.c create mode 100644 drivers/iommu/bcm2712-iommu-cache.c create mode 100644 drivers/iommu/bcm2712-iommu.c create mode 100644 drivers/iommu/bcm2712-iommu.h @@ -1642,12 +1739,51 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 drivers/media/i2c/arducam_64mp.c create mode 100644 drivers/media/i2c/bu64754.c create mode 100644 drivers/media/i2c/imx477.c + create mode 100644 drivers/media/i2c/imx500.c create mode 100644 drivers/media/i2c/imx519.c create mode 100644 drivers/media/i2c/imx708.c create mode 100644 drivers/media/i2c/irs1125.c create mode 100644 drivers/media/i2c/irs1125.h create mode 100644 drivers/media/i2c/ov2311.c create mode 100644 drivers/media/i2c/ov64a40.c + create mode 100644 drivers/media/pci/hailo/Kconfig + create mode 100644 drivers/media/pci/hailo/Makefile + create mode 100644 drivers/media/pci/hailo/common/fw_operation.c + create mode 100644 drivers/media/pci/hailo/common/fw_operation.h + create mode 100644 drivers/media/pci/hailo/common/fw_validation.c + create mode 100644 drivers/media/pci/hailo/common/fw_validation.h + create mode 100644 drivers/media/pci/hailo/common/hailo_ioctl_common.h + create mode 100644 drivers/media/pci/hailo/common/hailo_pcie_version.h + create mode 100644 drivers/media/pci/hailo/common/hailo_resource.c + create mode 100644 drivers/media/pci/hailo/common/hailo_resource.h + create mode 100644 drivers/media/pci/hailo/common/pcie_common.c + create mode 100644 drivers/media/pci/hailo/common/pcie_common.h + create mode 100644 drivers/media/pci/hailo/common/utils.h + create mode 100644 drivers/media/pci/hailo/common/vdma_common.c + create mode 100644 drivers/media/pci/hailo/common/vdma_common.h + create mode 100755 drivers/media/pci/hailo/include/hailo_pcie_version.h + create mode 100644 drivers/media/pci/hailo/src/fops.c + create mode 100644 drivers/media/pci/hailo/src/fops.h + create mode 100755 drivers/media/pci/hailo/src/pci_soc_ioctl.c + create mode 100755 drivers/media/pci/hailo/src/pci_soc_ioctl.h + create mode 100644 drivers/media/pci/hailo/src/pcie.c + create mode 100644 drivers/media/pci/hailo/src/pcie.h + create mode 100644 drivers/media/pci/hailo/src/sysfs.c + create mode 100644 drivers/media/pci/hailo/src/sysfs.h + create mode 100644 drivers/media/pci/hailo/src/utils.c + create mode 100644 drivers/media/pci/hailo/src/utils.h + create mode 100644 drivers/media/pci/hailo/utils/compact.h + create mode 100644 drivers/media/pci/hailo/utils/fw_common.h + create mode 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.c + create mode 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.h + create mode 100644 drivers/media/pci/hailo/utils/logs.c + create mode 100644 drivers/media/pci/hailo/utils/logs.h + create mode 100644 drivers/media/pci/hailo/vdma/ioctl.c + create mode 100644 drivers/media/pci/hailo/vdma/ioctl.h + create mode 100644 drivers/media/pci/hailo/vdma/memory.c + create mode 100644 drivers/media/pci/hailo/vdma/memory.h + create mode 100644 drivers/media/pci/hailo/vdma/vdma.c + create mode 100644 drivers/media/pci/hailo/vdma/vdma.h create mode 100644 drivers/media/platform/bcm2835/Kconfig create mode 100644 drivers/media/platform/bcm2835/Makefile create mode 100644 drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -1657,7 +1793,6 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Kconfig create mode 100644 drivers/media/platform/raspberrypi/pisp_be/Makefile create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be.c - create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h create mode 100644 drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Kconfig create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/Makefile @@ -1675,7 +1810,6 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_statistics.h create mode 100644 drivers/media/platform/raspberrypi/rp1_cfe/pisp_types.h create mode 100644 drivers/mfd/rp1.c - create mode 100644 drivers/mfd/rpisense-core.c create mode 100644 drivers/misc/bcm2835_smi.c create mode 100644 drivers/mmc/host/bcm2835-mmc.c create mode 100644 drivers/mmc/host/bcm2835-sdhost.c @@ -1686,9 +1820,11 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2712.c create mode 100644 drivers/pinctrl/pinctrl-rp1.c create mode 100644 drivers/power/supply/rpi_poe_power.c + create mode 100644 drivers/pwm/pwm-gpio.c create mode 100644 drivers/pwm/pwm-rp1.c create mode 100644 drivers/regulator/rpi-panel-v2-regulator.c create mode 100644 drivers/rtc/rtc-rpi.c + create mode 100644 drivers/spi/spi-rp2040-gpio-bridge.c create mode 100644 drivers/staging/media/rpivid/Kconfig create mode 100644 drivers/staging/media/rpivid/Makefile create mode 100644 drivers/staging/media/rpivid/rpivid.c @@ -1788,7 +1924,6 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 include/dt-bindings/mfd/rp1.h create mode 100644 include/linux/broadcom/bcm2835_smi.h create mode 100644 include/linux/broadcom/vc_mem.h - create mode 100644 include/linux/mfd/rpisense/core.h create mode 100644 include/linux/mfd/rpisense/framebuffer.h create mode 100644 include/linux/mfd/rpisense/joystick.h create mode 100644 include/linux/platform_data/dma-bcm2708.h @@ -1796,6 +1931,8 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 include/media/raspberrypi/pisp_common.h create mode 100644 include/media/raspberrypi/pisp_types.h create mode 100644 include/uapi/linux/bcm2835-isp.h + create mode 100644 include/uapi/linux/media/raspberrypi/pisp_be_config.h + create mode 100644 include/uapi/linux/media/raspberrypi/pisp_common.h create mode 100644 net/wireless/certs/debian.hex create mode 100644 sound/soc/bcm/allo-boss-dac.c create mode 100644 sound/soc/bcm/allo-boss2-dac.c @@ -1813,6 +1950,8 @@ Subject: [PATCH] apply RPi patch of 6.6.30 (openEuler 6.6.0-26.0.0) create mode 100644 sound/soc/bcm/dionaudio_loco.c create mode 100644 sound/soc/bcm/fe-pi-audio.c create mode 100644 sound/soc/bcm/googlevoicehat-codec.c + create mode 100644 sound/soc/bcm/hifiberry_adc.c + create mode 100644 sound/soc/bcm/hifiberry_adc_controls.h create mode 100644 sound/soc/bcm/hifiberry_dacplus.c create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c @@ -1969,6 +2108,159 @@ index 000000000000..e1c19f78435e + bcm2835_isp_black_level bcm2835_isp_geq bcm2835_isp_gamma + bcm2835_isp_denoise bcm2835_isp_sharpen + bcm2835_isp_dpc_mode bcm2835_isp_dpc +diff --git a/Documentation/admin-guide/media/raspberrypi-pisp-be.dot b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot +new file mode 100644 +index 000000000000..55671dc1d443 +--- /dev/null ++++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot +@@ -0,0 +1,20 @@ ++digraph board { ++ rankdir=TB ++ n00000001 [label="{{ 0 | 1 | 2 | 7} | pispbe\n | { 3 | 4 | 5 | 6}}", shape=Mrecord, style=filled, fillcolor=green] ++ n00000001:port3 -> n0000001c [style=bold] ++ n00000001:port4 -> n00000022 [style=bold] ++ n00000001:port5 -> n00000028 [style=bold] ++ n00000001:port6 -> n0000002e [style=bold] ++ n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow] ++ n0000000a -> n00000001:port0 [style=bold] ++ n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow] ++ n00000010 -> n00000001:port1 [style=bold] ++ n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow] ++ n00000016 -> n00000001:port2 [style=bold] ++ n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow] ++ n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow] ++ n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow] ++ n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow] ++ n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow] ++ n00000034 -> n00000001:port7 [style=bold] ++} +diff --git a/Documentation/admin-guide/media/raspberrypi-pisp-be.rst b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst +new file mode 100644 +index 000000000000..0fcf46f26276 +--- /dev/null ++++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst +@@ -0,0 +1,109 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++========================================================= ++Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be) ++========================================================= ++ ++The PiSP Back End ++================= ++ ++The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads ++image data from DRAM memory and performs image processing as specified by the ++application through the parameters in a configuration buffer, before writing ++pixel data back to memory through two distinct output channels. ++ ++The ISP registers and programming model are documented in the `Raspberry Pi ++Image Signal Processor (PiSP) Specification document`_ ++ ++The PiSP Back End ISP processes images in tiles. The handling of image ++tessellation and the computation of low-level configuration parameters is ++realized by a free software library called `libpisp ++`_. ++ ++The full image processing pipeline, which involves capturing RAW Bayer data from ++an image sensor through a MIPI CSI-2 compatible capture interface, storing them ++in DRAM memory and processing them in the PiSP Back End to obtain images usable ++by an application is implemented in `libcamera `_ as ++part of the Raspberry Pi platform support. ++ ++The pisp-be driver ++================== ++ ++The Raspberry Pi PiSP Back End (pisp-be) driver is located under ++drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register ++a number of video capture and output devices, the `V4L2 subdev API` to register ++a subdevice for the ISP that connects the video devices in a single media graph ++realized using the `Media Controller (MC) API`. ++ ++The media topology registered by the `pisp-be` driver is represented below: ++ ++.. _pips-be-topology: ++ ++.. kernel-figure:: raspberrypi-pisp-be.dot ++ :alt: Diagram of the default media pipeline topology ++ :align: center ++ ++ ++The media graph registers the following video device nodes: ++ ++- pispbe-input: output device for images to be submitted to the ISP for ++ processing. ++- pispbe-tdn_input: output device for temporal denoise. ++- pispbe-stitch_input: output device for image stitching (HDR). ++- pispbe-output0: first capture device for processed images. ++- pispbe-output1: second capture device for processed images. ++- pispbe-tdn_output: capture device for temporal denoise. ++- pispbe-stitch_output: capture device for image stitching (HDR). ++- pispbe-config: output device for ISP configuration parameters. ++ ++pispbe-input ++------------ ++ ++Images to be processed by the ISP are queued to the `pispbe-input` output device ++node. For a list of image formats supported as input to the ISP refer to the ++`Raspberry Pi Image Signal Processor (PiSP) Specification document`_. ++ ++pispbe-tdn_input, pispbe-tdn_output ++----------------------------------- ++ ++The `pispbe-tdn_input` output video device receives images to be processed by ++the temporal denoise block which are captured from the `pispbe-tdn_output` ++capture video device. Userspace is responsible for maintaining queues on both ++devices, and ensuring that buffers completed on the output are queued to the ++input. ++ ++pispbe-stitch_input, pispbe-stitch_output ++----------------------------------------- ++ ++To realize HDR (high dynamic range) image processing the image stitching and ++tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory ++and the `pispbe-stitch_input` receives the previously written frame to process ++it along with the current input image. Userspace is responsible for maintaining ++queues on both devices, and ensuring that buffers completed on the output are ++queued to the input. ++ ++pispbe-output0, pispbe-output1 ++------------------------------ ++ ++The two capture devices write to memory the pixel data as processed by the ISP. ++ ++pispbe-config ++------------- ++ ++The `pispbe-config` output video devices receives a buffer of configuration ++parameters that define the desired image processing to be performed by the ISP. ++ ++The format of the ISP configuration parameter is defined by ++:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is ++described in the `Raspberry Pi Image Signal Processor (PiSP) Specification ++document`_. ++ ++ISP configuration ++================= ++ ++The ISP configuration is described solely by the content of the parameters ++buffer. The only parameter that userspace needs to configure using the V4L2 API ++is the image format on the output and capture video devices for validation of ++the content of the parameters buffer. ++ ++.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf +diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst +index 1c41f87c3917..53e075cbdf70 100644 +--- a/Documentation/admin-guide/media/v4l-drivers.rst ++++ b/Documentation/admin-guide/media/v4l-drivers.rst +@@ -21,6 +21,7 @@ Video4Linux (V4L) driver-specific documentation + omap4_camera + philips + qcom_camss ++ raspberrypi-pisp-be + rcar-fdp1 + rkisp1 + saa7134 diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml index 5b35adf34c7b..6d11f5955b51 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml @@ -3288,6 +3580,144 @@ index 80d24220baa0..3415b26b5991 100644 assigned-clocks: true assigned-clock-parents: true +diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml +new file mode 100644 +index 000000000000..b8538ae6c80f +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml +@@ -0,0 +1,132 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/sony,imx500.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony CMOS Digital Image Sensor and CNN ++ ++maintainers: ++ - Raspberry Pi ++ ++description: |- ++ The Sony IMX500 is a stacked 1/2.3-inch CMOS digital image sensor and inbuilt ++ AI processor with an active array CNN (Convolutional Neural Network) inference ++ engine. The native sensor size is 4056H x 3040V, and the module also contains ++ an in-built ISP for the CNN. The module is programmable through an I2C ++ interface with firmware and neural network uploads being made over SPI. The ++ default I2C address is 0x1A, with an address of 0x10 being selectable via ++ SLASEL. The module also has a second I2C interface available with a fixed ++ address of 0x36. Image data is sent through MIPI CSI-2, which is configured ++ as either 2 or 4 data lanes. ++ ++properties: ++ compatible: ++ const: sony,imx500 ++ ++ reg: ++ description: I2C device address ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ description: |- ++ Input clock (12 to 27 MHz) ++ items: ++ - const: inck ++ ++ interrupts: ++ maxItems: 1 ++ ++ vana-supply: ++ description: Supply voltage (analog) - 2.7 V ++ ++ vdig-supply: ++ description: Supply voltage (digital) - 0.84 V ++ ++ vif-supply: ++ description: Supply voltage (interface) - 1.8 V ++ ++ reset-gpios: ++ description: |- ++ Sensor reset (XCLR) GPIO ++ ++ Chip clear in lieu of built-in power on reset. To be set 'High' after ++ power supplies are brought up and INCK supplied. ++ ++ port: ++ $ref: /schemas/graph.yaml#/$defs/port-base ++ additionalProperties: false ++ description: | ++ Video output port ++ ++ properties: ++ endpoint: ++ $ref: /schemas/media/video-interfaces.yaml# ++ type: object ++ unevaluatedProperties: false ++ properties: ++ data-lanes: ++ items: ++ - const: 2 ++ - const: 4 ++ clock-noncontinuous: true ++ link-frequencies: true ++ required: ++ - link-frequencies ++ - data-lanes ++ ++ spi: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: |- ++ SPI peripheral ++ ++ Optional SPI peripheral for uploading firmware and network weights to AI ++ processor. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - vana-supply ++ - vdig-supply ++ - vif-supply ++ - port ++ ++examples: ++ - | ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imx500: sensor@1a { ++ compatible = "sony,imx500"; ++ reg = <0x1a>; ++ ++ clocks = <&imx500_clk>; ++ clock-names = "inck"; ++ ++ vana-supply = <&imx500_vana>; /* 2.7 +/- 0.1 V */ ++ vdig-supply = <&imx500_vdig>; /* 0.84 +/- 0.04 V */ ++ vif-supply = <&imx500_vif>; /* 1.8 +/- 0.1 V */ ++ ++ reset-gpios = <&gpio_sensor 0 GPIO_ACTIVE_LOW>; ++ ++ port { ++ imx500_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <499500000>; ++ }; ++ }; ++ }; ++ }; ++ ++... ++ diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx708.yaml new file mode 100644 index 000000000000..286aad2e8c69 @@ -3422,6 +3852,75 @@ index 000000000000..286aad2e8c69 + }; + }; +... +diff --git a/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml +new file mode 100644 +index 000000000000..1fc62a1d8eda +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml +@@ -0,0 +1,63 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End ++ ++maintainers: ++ - Raspberry Pi Kernel Maintenance ++ - Jacopo Mondi ++ ++description: | ++ The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image ++ processor that fetches images in Bayer or Grayscale format from DRAM memory ++ in tiles and produces images consumable by applications. ++ ++ The full ISP documentation is available at ++ https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - brcm,bcm2712-pispbe ++ - const: raspberrypi,pispbe ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ iommus: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ isp@880000 { ++ compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&firmware_clocks 7>; ++ iommus = <&iommu2>; ++ }; ++ }; diff --git a/Documentation/devicetree/bindings/media/rpivid_hevc.yaml b/Documentation/devicetree/bindings/media/rpivid_hevc.yaml new file mode 100644 index 000000000000..ce6b81a10303 @@ -3898,6 +4397,104 @@ index 3aae3b41bd8e..77006a4aec4a 100644 Examples: +diff --git a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml +index a48d040b0a4f..6e50851ff70f 100644 +--- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml ++++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml +@@ -69,6 +69,10 @@ properties: + - description: RX DMA Channel + minItems: 1 + ++ dma-maxburst: ++ description: FIFO DMA burst threshold limit ++ maxItems: 1 ++ + dma-names: + items: + - const: tx +diff --git a/Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml b/Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml +new file mode 100644 +index 000000000000..d6af6db169d5 +--- /dev/null ++++ b/Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml +@@ -0,0 +1,77 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/spi/raspberrypi,rp2040-gpio-bridge.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raspberry Pi RP2040 GPIO Bridge ++ ++maintainers: ++ - Raspberry Pi ++ ++description: |- ++ The Raspberry Pi PR2040 GPIO bridge can be used as a GPIO expander and ++ Tx-only SPI master. ++ ++properties: ++ reg: ++ description: I2C slave address ++ const: 0x40 ++ ++ compatible: ++ const: raspberrypi,rp2040-gpio-bridge ++ ++ power-supply: ++ description: Phandle to the regulator that powers the RP2040. ++ ++ '#address-cells': ++ const: 1 ++ ++ '#size-cells': ++ const: 0 ++ ++ '#gpio-cells': ++ const: 2 ++ ++ gpio-controller: true ++ ++ fast_xfer_requires_i2c_lock: ++ description: Set if I2C bus should be locked during fast transfer. ++ ++ fast_xfer_recv_gpio_base: ++ description: RP2040 GPIO base for fast transfer pair. ++ ++ fast_xfer-gpios: ++ description: RP1 GPIOs to use for fast transfer clock and data. ++ ++required: ++ - reg ++ - compatible ++ - power-supply ++ - '#gpio-cells' ++ - gpio-controller ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ spi@40 { ++ reg = <0x40>; ++ compatible = "raspberrypi,rp2040-gpio-bridge"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ power-supply = <&cam_dummy_reg>; ++ ++ #gpio-cells = <2>; ++ gpio-controller; ++ }; ++ }; ++ ++... ++ diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.yaml b/Documentation/devicetree/bindings/spi/spi-gpio.yaml index 9ce1df93d4c3..d911c203fa45 100644 --- a/Documentation/devicetree/bindings/spi/spi-gpio.yaml @@ -4474,17 +5071,29 @@ index 000000000000..5fa43e064307 +better suited to different use patterns. The firmware interface is what's +intended to be used by hardware managers in the kernel, while the copy interface +make sense for developers (since it avoids problems with namespaces). +diff --git a/Documentation/driver-api/gpio/drivers-on-gpio.rst b/Documentation/driver-api/gpio/drivers-on-gpio.rst +index af632d764ac6..95572d2a94ce 100644 +--- a/Documentation/driver-api/gpio/drivers-on-gpio.rst ++++ b/Documentation/driver-api/gpio/drivers-on-gpio.rst +@@ -27,7 +27,12 @@ hardware descriptions such as device tree or ACPI: + to the lines for a more permanent solution of this type. + + - gpio-beeper: drivers/input/misc/gpio-beeper.c is used to provide a beep from +- an external speaker connected to a GPIO line. ++ an external speaker connected to a GPIO line. (If the beep is controlled by ++ off/on, for an actual PWM waveform, see pwm-gpio below.) ++ ++- pwm-gpio: drivers/pwm/pwm-gpio.c is used to toggle a GPIO with a high ++ resolution timer producing a PWM waveform on the GPIO line, as well as ++ Linux high resolution timers can do. + + - extcon-gpio: drivers/extcon/extcon-gpio.c is used when you need to read an + external connector status, such as a headset line for an audio driver or an diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst -index 3fdc95f7a1d1..c68ed828fba9 100644 +index ed5ec9816538..c68ed828fba9 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst -@@ -41,11 +41,20 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. - - After being requested, a PWM has to be configured using:: - -- int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); -+ int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state); - +@@ -46,6 +46,15 @@ After being requested, a PWM has to be configured using:: This API controls both the PWM period/duty_cycle config and the enable/disable state. @@ -4500,23 +5109,6 @@ index 3fdc95f7a1d1..c68ed828fba9 100644 As a consumer, don't rely on the output's state for a disabled PWM. If it's easily possible, drivers are supposed to emit the inactive state, but some drivers cannot. If you rely on getting the inactive state, use .duty_cycle=0, -@@ -57,13 +66,13 @@ If supported by the driver, the signal can be optimized, for example to improve - EMI by phase shifting the individual channels of a chip. - - The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers --around pwm_apply_state() and should not be used if the user wants to change -+around pwm_apply_might_sleep() and should not be used if the user wants to change - several parameter at once. For example, if you see pwm_config() and - pwm_{enable,disable}() calls in the same function, this probably means you --should switch to pwm_apply_state(). -+should switch to pwm_apply_might_sleep(). - - The PWM user API also allows one to query the PWM state that was passed to the --last invocation of pwm_apply_state() using pwm_get_state(). Note this is -+last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is - different to what the driver has actually implemented if the request cannot be - satisfied exactly with the hardware in use. There is currently no way for - consumers to get the actually implemented settings. diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 6708d649afd7..65de8ab99c58 100644 --- a/Documentation/userspace-api/media/drivers/index.rst @@ -4530,21 +5122,96 @@ index 6708d649afd7..65de8ab99c58 100644 omap3isp-uapi st-vgxy61 diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst -index 0bb61fc5bc00..d421ccdfccfc 100644 +index 0bb61fc5bc00..178653874e44 100644 --- a/Documentation/userspace-api/media/v4l/meta-formats.rst +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst -@@ -12,9 +12,11 @@ These formats are used for the :ref:`metadata` interface only. +@@ -12,9 +12,12 @@ These formats are used for the :ref:`metadata` interface only. .. toctree:: :maxdepth: 1 + metafmt-bcm2835-isp-stats metafmt-d4xx metafmt-intel-ipu3 ++ metafmt-pisp-be metafmt-rkisp1 + metafmt-sensor-data metafmt-uvc metafmt-vsp1-hgo metafmt-vsp1-hgt +diff --git a/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst +new file mode 100644 +index 000000000000..3281fe366c86 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst +@@ -0,0 +1,56 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++.. _v4l2-meta-fmt-rpi-be-cfg: ++ ++************************ ++V4L2_META_FMT_RPI_BE_CFG ++************************ ++ ++Raspberry Pi PiSP Back End configuration format ++=============================================== ++ ++The Raspberry Pi PiSP Back End memory-to-memory image signal processor is ++configured by userspace by providing a buffer of configuration parameters ++to the `pispbe-config` output video device node using the ++:c:type:`v4l2_meta_format` interface. ++ ++The PiSP Back End processes images in tiles, and its configuration requires ++specifying two different sets of parameters by populating the members of ++:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file. ++ ++The `Raspberry Pi PiSP technical specification ++`_ ++provide detailed description of the ISP back end configuration and programming ++model. ++ ++Global configuration data ++------------------------- ++ ++The global configuration data describe how the pixels in a particular image are ++to be processed and is therefore shared across all the tiles of the image. So ++for example, LSC (Lens Shading Correction) or Denoise parameters would be common ++across all tiles from the same frame. ++ ++Global configuration data are passed to the ISP by populating the member of ++:c:type:`pisp_be_config`. ++ ++Tile parameters ++--------------- ++ ++As the ISP processes images in tiles, each set of tiles parameters describe how ++a single tile in an image is going to be processed. A single set of tile ++parameters consist of 160 bytes of data and to process a batch of tiles several ++sets of tiles parameters are required. ++ ++Tiles parameters are passed to the ISP by populating the member of ++``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`. ++ ++Raspberry Pi PiSP Back End uAPI data types ++========================================== ++ ++This section describes the data types exposed to userspace by the Raspberry Pi ++PiSP Back End. The section is informative only, for a detailed description of ++each field refer to the `Raspberry Pi PiSP technical specification ++`_. ++ ++.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst +index 2500413e5f43..ed3eb432967d 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst +@@ -20,6 +20,7 @@ orders. See also `the Wikipedia article on Bayer filter + :maxdepth: 1 + + pixfmt-srggb8 ++ pixfmt-srggb8-pisp-comp + pixfmt-srggb10 + pixfmt-srggb10p + pixfmt-srggb10alaw8 diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-bcm2835-isp-stats.rst new file mode 100644 index 000000000000..f974774c8252 @@ -4851,6 +5518,151 @@ index 000000000000..196ca33a5dff + + + +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +index b71b80d634d6..5ed4d62df909 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +@@ -996,6 +996,60 @@ arranged in little endian order. + + \normalsize + ++16 Bits Per Component ++===================== ++ ++These formats store an RGB triplet in six bytes, with 16 bits per component ++stored in memory in little endian byte order. They are named based on the order ++of the RGB components as stored in memory. For instance, RGB48 stores R\ ++:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from ++the DRM format nomenclature that instead uses the order of components as seen in ++the 48-bits little endian word. ++ ++.. raw:: latex ++ ++ \small ++ ++.. flat-table:: RGB Formats With 16 Bits Per Component ++ :header-rows: 1 ++ ++ * - Identifier ++ - Code ++ - Byte 0 ++ - Byte 1 ++ - Byte 2 ++ - Byte 3 ++ - Byte 4 ++ - Byte 5 ++ ++ * .. _V4L2-PIX-FMT-BGR48: ++ ++ - ``V4L2_PIX_FMT_BGR48`` ++ - 'BGR6' ++ ++ - B\ :sub:`7-0` ++ - B\ :sub:`15-8` ++ - G\ :sub:`7-0` ++ - G\ :sub:`15-8` ++ - R\ :sub:`7-0` ++ - R\ :sub:`15-8` ++ ++ * .. _V4L2-PIX-FMT-RGB48: ++ ++ - ``V4L2_PIX_FMT_RGB48`` ++ - 'RGB6' ++ ++ - R\ :sub:`7-0` ++ - R\ :sub:`15-8` ++ - G\ :sub:`7-0` ++ - G\ :sub:`15-8` ++ - B\ :sub:`7-0` ++ - B\ :sub:`15-8` ++ ++.. raw:: latex ++ ++ \normalsize ++ + Deprecated RGB Formats + ====================== + +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst +new file mode 100644 +index 000000000000..5a82a15559d6 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst +@@ -0,0 +1,74 @@ ++.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later ++ ++.. _v4l2-pix-fmt-pisp-comp1-rggb: ++.. _v4l2-pix-fmt-pisp-comp1-grbg: ++.. _v4l2-pix-fmt-pisp-comp1-gbrg: ++.. _v4l2-pix-fmt-pisp-comp1-bggr: ++.. _v4l2-pix-fmt-pisp-comp1-mono: ++.. _v4l2-pix-fmt-pisp-comp2-rggb: ++.. _v4l2-pix-fmt-pisp-comp2-grbg: ++.. _v4l2-pix-fmt-pisp-comp2-gbrg: ++.. _v4l2-pix-fmt-pisp-comp2-bggr: ++.. _v4l2-pix-fmt-pisp-comp2-mono: ++ ++************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** ++V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M') ++************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** ++ ++================================================ ++Raspberry Pi PiSP compressed 8-bit Bayer formats ++================================================ ++ ++Description ++=========== ++ ++The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer ++formats. A black-level offset may be subtracted to improve compression ++efficiency; the nominal black level and amount of offset must be signalled out ++of band. Each scanline is padded to a multiple of 8 pixels wide, and each block ++of 8 horizontally-contiguous pixels is coded using 8 bytes. ++ ++Mode 1 uses a quantization and delta-based coding scheme which preserves up to ++12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL ++chords, preserving up to 12 significant bits. Mode 3 combines both companding ++(with 4 chords) and the delta scheme, preserving up to 14 significant bits. ++ ++The remainder of this description applies to Modes 1 and 3. ++ ++Each block of 8 pixels is separated into even and odd phases of 4 pixels, ++coded independently by 32-bit words at successive locations in memory. ++The two LS bits of each 32-bit word give its "quantization mode". ++ ++In quantization mode 0, the lowest 321 quantization levels are multiples of ++FSD/4096 and the remaining levels are successive multiples of FSD/2048. ++Quantization modes 1 and 2 use linear quantization with step sizes of ++FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized ++independently, with rounding to the nearest level. ++In quantization mode 2 where the middle two samples have quantized values ++(q1,q2) both in the range [384..511], they are coded using 9 bits for q1 ++followed by 7 bits for (q2 & 127). Otherwise, for quantization modes ++0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range ++[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127]. ++ ++Each of the outer samples (q0,q3) is encoded using a 7-bit field based ++on its inner neighbour q1 or q2. In quantization mode 2 where the inner ++sample has a quantized value in the range [448..511], the field value is ++(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample ++is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2. ++Each of these values must be in the range [0..127]. All these fields ++of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order ++to give a 32-bit word with LE byte order. ++ ++Quantization mode 3 has a "7.5-bit" escape, used when none of the above ++encodings will fit. Each pixel value is quantized to the nearest of 176 ++levels, where the lowest 95 levels are multiples of FSD/256 and the ++remaining levels are multiples of FSD/128 (level 175 represents values ++very close to FSD and may require saturating arithmetic to decode). ++ ++Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded ++by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15). ++Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}. ++ ++An implementation of a software decoder of compressed formats is available ++in `Raspberry Pi camera applications code base ++`_. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst b/Documentation/userspace-api/media/v4l/pixfmt-y12p.rst new file mode 100644 index 000000000000..3704f9180fd7 @@ -4962,6 +5774,18 @@ index 000000000000..27fe14c9a9eb + - Y'\ :sub:`03low bits 5--0`\ (bits 7--2) + + Y'\ :sub:`02low bits 5--4`\ (bits 1--0) +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst +index cf8e4dfbfbd4..93514bd77398 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst +@@ -161,3 +161,7 @@ are often referred to as greyscale formats. + For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with + padding zeros in the 4 low bits, in contrast to the Y12 format, which has + its padding located in the most significant bits of the 16 bit word. ++ ++ The 'P' variations of the Y10, Y12 and Y14 formats are packed according to ++ the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2 ++ specification. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 1840224faa41..56ef9ee9c0e1 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -5191,10 +6015,10 @@ index 24b34cdfa6fe..44589ac3e909 100644 + pixfmt-nv24 pixfmt-m420 diff --git a/MAINTAINERS b/MAINTAINERS -index 1c70622103e0..2e813db650d1 100644 +index 008a26b0f027..b6eee668e0fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -1563,6 +1563,22 @@ S: Maintained +@@ -1569,6 +1569,22 @@ S: Maintained F: drivers/net/arcnet/ F: include/uapi/linux/if_arcnet.h @@ -5217,7 +6041,7 @@ index 1c70622103e0..2e813db650d1 100644 ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS) M: Arnd Bergmann M: Olof Johansson -@@ -3916,6 +3932,29 @@ N: bcm113* +@@ -3922,6 +3938,29 @@ N: bcm113* N: bcm216* N: kona @@ -5247,7 +6071,7 @@ index 1c70622103e0..2e813db650d1 100644 BROADCOM BCM47XX MIPS ARCHITECTURE M: Hauke Mehrtens M: RafaÅ‚ MiÅ‚ecki -@@ -15868,6 +15907,14 @@ S: Maintained +@@ -15908,6 +15947,14 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov5695.c @@ -5262,16 +6086,44 @@ index 1c70622103e0..2e813db650d1 100644 OMNIVISION OV7670 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -@@ -17426,7 +17473,7 @@ F: drivers/video/backlight/pwm_bl.c +@@ -17477,7 +17524,7 @@ F: drivers/video/backlight/pwm_bl.c F: include/dt-bindings/pwm/ F: include/linux/pwm.h F: include/linux/pwm_backlight.h --K: pwm_(config|apply_state|ops) +-K: pwm_(config|apply_might_sleep|ops) +K: pwm_(config|apply_might_sleep|apply_atomic|ops) PXA GPIO DRIVER M: Robert Jarzmik -@@ -18618,6 +18665,13 @@ S: Supported +@@ -18067,6 +18114,12 @@ F: drivers/ras/ + F: include/linux/ras.h + F: include/ras/ras_event.h + ++RASPBERRY PI RP2040 GPIO BRIDGE DRIVER ++M: Raspberry Pi Kernel Maintenance ++S: Maintained ++F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml ++F: drivers/spi/spi-rp2040-gpio-bridge.c ++ + RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER + L: linux-wireless@vger.kernel.org + S: Orphan +@@ -18078,6 +18131,14 @@ L: linux-edac@vger.kernel.org + S: Maintained + F: drivers/ras/amd/fmpm.c + ++RASPBERRY PI PISP BACK END ++M: Jacopo Mondi ++L: Raspberry Pi Kernel Maintenance ++L: linux-media@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml ++F: include/uapi/linux/media/raspberrypi/ ++ + RC-CORE / LIRC FRAMEWORK + M: Sean Young + L: linux-media@vger.kernel.org +@@ -18675,6 +18736,13 @@ S: Supported F: drivers/iio/light/rohm-bu27008.c F: drivers/iio/light/rohm-bu27034.c @@ -5285,7 +6137,7 @@ index 1c70622103e0..2e813db650d1 100644 ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS M: Marek Vasut L: linux-kernel@vger.kernel.org -@@ -20011,7 +20065,7 @@ M: Sakari Ailus +@@ -20068,7 +20136,7 @@ M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git @@ -5294,7 +6146,7 @@ index 1c70622103e0..2e813db650d1 100644 F: drivers/media/i2c/imx258.c SONY IMX274 SENSOR DRIVER -@@ -20088,6 +20142,31 @@ T: git git://linuxtv.org/media_tree.git +@@ -20145,6 +20213,39 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml F: drivers/media/i2c/imx415.c @@ -5307,6 +6159,14 @@ index 1c70622103e0..2e813db650d1 100644 +F: Documentation/devicetree/bindings/media/i2c/imx477.yaml +F: drivers/media/i2c/imx477.c + ++SONY IMX500 SENSOR DRIVER ++M: Raspberry Pi Kernel Maintenance ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml ++F: drivers/media/i2c/imx500.c ++ +SONY IMX519 SENSOR DRIVER +M: Arducam Kernel Maintenance +L: linux-media@vger.kernel.org @@ -6072,10 +6932,10 @@ index 000000000000..b8459fd0f497 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi new file mode 100644 -index 000000000000..98555528adae +index 000000000000..87a6c00bd056 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi -@@ -0,0 +1,38 @@ +@@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 + +&uart0 { @@ -6101,6 +6961,10 @@ index 000000000000..98555528adae +}; + +/ { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; ++ }; ++ + aliases { + bluetooth = &bt; + }; @@ -6296,10 +7160,10 @@ index 000000000000..fde85c8c7dca +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi new file mode 100644 -index 000000000000..10fd4475dd5e +index 000000000000..8d3e42bfe4f0 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-cm.dtsi -@@ -0,0 +1,27 @@ +@@ -0,0 +1,23 @@ +#include "bcm2708.dtsi" +#include "bcm2708-rpi.dtsi" +#include "bcm283x-rpi-led-deprecated.dtsi" @@ -6321,18 +7185,14 @@ index 000000000000..10fd4475dd5e + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; -+ cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; -+ cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts new file mode 100644 -index 000000000000..011d0fa4c9c0 +index 000000000000..f6d4e2c73df9 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts -@@ -0,0 +1,254 @@ +@@ -0,0 +1,250 @@ +/dts-v1/; + +#include "bcm2708.dtsi" @@ -6346,10 +7206,6 @@ index 000000000000..011d0fa4c9c0 + compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; + model = "Raspberry Pi Zero W"; + -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + aliases { + serial0 = &uart1; + serial1 = &uart0; @@ -6784,10 +7640,10 @@ index 000000000000..1721be8dbe20 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi new file mode 100644 -index 000000000000..f4949a07272b +index 000000000000..f4aedb5c532b --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi.dtsi -@@ -0,0 +1,57 @@ +@@ -0,0 +1,63 @@ +/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */ + +#define i2c0 i2c0mux @@ -6816,18 +7672,24 @@ index 000000000000..f4949a07272b +}; + +&soc { -+ nvmem_otp: nvmem_otp { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <0 192>; -+ status = "okay"; -+ }; ++ nvmem { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; + -+ nvmem_cust: nvmem_cust { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <1 8>; -+ status = "okay"; ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 192>; ++ status = "okay"; ++ }; ++ ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; + }; +}; + @@ -7082,10 +7944,10 @@ index 000000000000..7796e545da43 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts new file mode 100644 -index 000000000000..5a5f910edba1 +index 000000000000..36d00aa889a3 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2709-rpi-cm2.dts -@@ -0,0 +1,219 @@ +@@ -0,0 +1,215 @@ +/dts-v1/; + +#include "bcm2709.dtsi" @@ -7299,10 +8161,6 @@ index 000000000000..5a5f910edba1 + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; -+ cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; -+ cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2709-rpi.dtsi @@ -7356,10 +8214,10 @@ index 000000000000..868f65f922ff +}; diff --git a/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi new file mode 100644 -index 000000000000..bc533f329640 +index 000000000000..d4a4e97c18b4 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm270x-rpi.dtsi -@@ -0,0 +1,201 @@ +@@ -0,0 +1,208 @@ +/* Downstream modifications to bcm2835-rpi.dtsi */ + +/ { @@ -7462,16 +8320,23 @@ index 000000000000..bc533f329640 + + cam1_sync = <&csi1>, "sync-gpios:0=", <&gpio>, + <&csi1>, "sync-gpios:4", -+ <&csi1>, "sync-gpios:8=0", ; ++ <&csi1>, "sync-gpios:8=", ; + cam1_sync_inverted = <&csi1>, "sync-gpios:0=", <&gpio>, + <&csi1>, "sync-gpios:4", -+ <&csi1>, "sync-gpios:8=0", ; ++ <&csi1>, "sync-gpios:8=", ; + cam0_sync = <&csi0>, "sync-gpios:0=", <&gpio>, + <&csi0>, "sync-gpios:4", -+ <&csi0>, "sync-gpios:8=0", ; ++ <&csi0>, "sync-gpios:8=", ; + cam0_sync_inverted = <&csi0>, "sync-gpios:0=", <&gpio>, + <&csi0>, "sync-gpios:4", -+ <&csi0>, "sync-gpios:8=0", ; ++ <&csi0>, "sync-gpios:8=", ; ++ ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4", ++ <&cam0_reg>,"gpio:0=", <&gpio>; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4", ++ <&cam1_reg>,"gpio:0=", <&gpio>; + + strict_gpiod = <&chosen>, "bootargs=pinctrl_bcm2835.persist_gpio_outputs=n"; + }; @@ -7563,7 +8428,7 @@ index 000000000000..bc533f329640 +#endif diff --git a/arch/arm/boot/dts/broadcom/bcm270x.dtsi b/arch/arm/boot/dts/broadcom/bcm270x.dtsi new file mode 100644 -index 000000000000..c318080eb883 +index 000000000000..e077bd271123 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm270x.dtsi @@ -0,0 +1,294 @@ @@ -7573,7 +8438,7 @@ index 000000000000..c318080eb883 +/ { + chosen: chosen { + // Disable audio by default -+ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; + stdout-path = "serial0:115200n8"; + }; + @@ -8073,10 +8938,10 @@ index 000000000000..ce48eb6073f0 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts new file mode 100644 -index 000000000000..1afbb9011702 +index 000000000000..8973985e9902 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts -@@ -0,0 +1,299 @@ +@@ -0,0 +1,295 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -8091,10 +8956,6 @@ index 000000000000..1afbb9011702 + compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B+"; + -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + aliases { + serial0 = &uart1; + serial1 = &uart0; @@ -8378,10 +9239,10 @@ index 000000000000..1afbb9011702 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts new file mode 100644 -index 000000000000..b893affe6997 +index 000000000000..35e6e9900083 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts -@@ -0,0 +1,297 @@ +@@ -0,0 +1,293 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -8396,10 +9257,6 @@ index 000000000000..b893affe6997 + compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B"; + -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + aliases { + serial0 = &uart1; + serial1 = &uart0; @@ -8681,10 +9538,10 @@ index 000000000000..b893affe6997 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts new file mode 100644 -index 000000000000..8206368b0aff +index 000000000000..0d6e9e61f877 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-cm3.dts -@@ -0,0 +1,219 @@ +@@ -0,0 +1,215 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -8898,18 +9755,14 @@ index 000000000000..8206368b0aff + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; -+ cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; -+ cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts new file mode 100644 -index 000000000000..25182d73f244 +index 000000000000..16971e50229f --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts -@@ -0,0 +1,261 @@ +@@ -0,0 +1,257 @@ +/dts-v1/; + +#include "bcm2710.dtsi" @@ -8923,10 +9776,6 @@ index 000000000000..25182d73f244 + compatible = "raspberrypi,model-zero-2-w", "brcm,bcm2837"; + model = "Raspberry Pi Zero 2 W"; + -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + aliases { + serial0 = &uart1; + serial1 = &uart0; @@ -9217,7 +10066,7 @@ index 000000000000..bdcdbb51fab8 + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts -index d5f8823230db..d3a3a1e4d4c6 100644 +index d5f8823230db..75ce412a85dd 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts @@ -1,10 +1,16 @@ @@ -9280,7 +10129,7 @@ index d5f8823230db..d3a3a1e4d4c6 100644 "GPIO16", "GPIO17", "GPIO18", -@@ -241,3 +247,233 @@ &vec { +@@ -241,3 +247,229 @@ &vec { &wifi_pwrseq { reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; }; @@ -9302,10 +10151,6 @@ index d5f8823230db..d3a3a1e4d4c6 100644 +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" + +/ { -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + /delete-node/ wifi-pwrseq; +}; + @@ -9576,10 +10421,10 @@ index 5a2869a18bd5..d5b81b889018 100644 +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts new file mode 100644 -index 000000000000..9fdb9278c5a2 +index 000000000000..678b37518fdc --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts -@@ -0,0 +1,510 @@ +@@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#define BCM2711 @@ -9856,10 +10701,6 @@ index 000000000000..9fdb9278c5a2 +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" + +/ { -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0"; -+ }; -+ + /delete-node/ wifi-pwrseq; +}; + @@ -10080,22 +10921,15 @@ index 000000000000..9fdb9278c5a2 + <&ant2>, "output-high?=off", + <&ant2>, "output-low?=on"; + -+ cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpio:4", -+ <&cam0_reg>,"gpio:0=", <&gpio>; -+ cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpio:4", -+ <&cam1_reg>,"gpio:0=", <&gpio>; -+ + pcie_tperst_clk_ms = <&pcie0>,"brcm,tperst-clk-ms:0"; + }; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts new file mode 100644 -index 000000000000..e62932f1a5a1 +index 000000000000..71d228414b76 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts -@@ -0,0 +1,298 @@ +@@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#define BCM2711 @@ -10246,7 +11080,7 @@ index 000000000000..e62932f1a5a1 + +/ { + chosen { -+ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0"; ++ bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave"; + }; + + aliases { @@ -10387,24 +11221,20 @@ index 000000000000..e62932f1a5a1 + act_led_gpio = <&led_act>,"gpios:4"; + act_led_activelow = <&led_act>,"gpios:8"; + act_led_trigger = <&led_act>,"linux,default-trigger"; -+ -+ cam0_reg = <&cam0_reg>,"status"; -+ cam0_reg_gpio = <&cam0_reg>,"gpio:4"; -+ cam1_reg = <&cam1_reg>,"status"; -+ cam1_reg_gpio = <&cam1_reg>,"gpio:4"; + }; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi new file mode 100644 -index 000000000000..c45685339992 +index 000000000000..eb3abcdbae6b --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi -@@ -0,0 +1,561 @@ +@@ -0,0 +1,567 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "bcm270x-rpi.dtsi" + +/ { -+ chosen: chosen { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave"; + }; + + __overrides__ { @@ -10492,26 +11322,31 @@ index 000000000000..c45685339992 + /* Add the physical <-> DMA mapping for the I/O space */ + dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>, + <0x7c000000 0x0 0xfc000000 0x03800000>; ++ nvmem { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; + -+ nvmem_otp: nvmem_otp { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <0 166>; -+ status = "okay"; -+ }; ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 166>; ++ status = "okay"; ++ }; + -+ nvmem_cust: nvmem_cust { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <1 8>; -+ status = "okay"; -+ }; ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; + -+ nvmem_priv: nvmem_priv { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <3 8>; -+ status = "okay"; ++ nvmem_priv: nvmem_priv { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <3 8>; ++ status = "okay"; ++ }; + }; +}; + @@ -10520,7 +11355,7 @@ index 000000000000..c45685339992 + + ranges = <0x0 0x7c000000 0x0 0xfc000000 0x0 0x03800000>, + <0x0 0x40000000 0x0 0xff800000 0x0 0x00800000>, -+ <0x6 0x00000000 0x6 0x00000000 0x0 0x40000000>, ++ <0x6 0x00000000 0x6 0x00000000 0x0 0x80000000>, + <0x0 0x00000000 0x0 0x00000000 0x0 0xfc000000>; + dma-ranges = <0x4 0x7c000000 0x0 0xfc000000 0x0 0x03800000>, + <0x0 0x00000000 0x0 0x00000000 0x4 0x00000000>; @@ -10564,8 +11399,8 @@ index 000000000000..c45685339992 + +&pcie0 { + reg = <0x0 0x7d500000 0x0 0x9310>; -+ ranges = <0x02000000 0x0 0xc0000000 0x6 0x00000000 -+ 0x0 0x40000000>; ++ ranges = <0x02000000 0x0 0x80000000 0x6 0x00000000 ++ 0x0 0x80000000>; +}; + +&genet { @@ -11005,3583 +11840,12 @@ index 4a379a14966d..09dbe7b3ca39 100644 #pwm-cells = <3>; status = "disabled"; }; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts -new file mode 100644 -index 000000000000..84edb08b1197 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-5-b.dts -@@ -0,0 +1,863 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/dts-v1/; -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define i2c0 _i2c0 -+#define i2c3 _i2c3 -+#define i2c4 _i2c4 -+#define i2c5 _i2c5 -+#define i2c6 _i2c6 -+#define i2c8 _i2c8 -+#define i2s _i2s -+#define pwm0 _pwm0 -+#define pwm1 _pwm1 -+#define spi0 _spi0 -+#define spi3 _spi3 -+#define spi4 _spi4 -+#define spi5 _spi5 -+#define spi6 _spi6 -+#define uart0 _uart0 -+#define uart2 _uart2 -+#define uart5 _uart5 -+ -+#include "bcm2712.dtsi" -+ -+#undef i2c0 -+#undef i2c3 -+#undef i2c4 -+#undef i2c5 -+#undef i2c6 -+#undef i2c8 -+#undef i2s -+#undef pwm0 -+#undef pwm1 -+#undef spi0 -+#undef spi3 -+#undef spi4 -+#undef spi5 -+#undef spi6 -+#undef uart0 -+#undef uart2 -+#undef uart3 -+#undef uart4 -+#undef uart5 -+ -+/ { -+ compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; -+ model = "Raspberry Pi 5"; -+ -+ /* Will be filled by the bootloader */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0 0 0x28000000>; -+ }; -+ -+ leds: leds { -+ compatible = "gpio-leds"; -+ -+ led_pwr: led-pwr { -+ label = "PWR"; -+ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ linux,default-trigger = "none"; -+ }; -+ -+ led_act: led-act { -+ label = "ACT"; -+ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ linux,default-trigger = "mmc0"; -+ }; -+ }; -+ -+ sd_io_1v8_reg: sd_io_1v8_reg { -+ compatible = "regulator-gpio"; -+ regulator-name = "vdd-sd-io"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ regulator-settling-time-us = <5000>; -+ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; -+ states = <1800000 0x1 -+ 3300000 0x0>; -+ status = "okay"; -+ }; -+ -+ sd_vcc_reg: sd_vcc_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc-sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ enable-active-high; -+ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+ -+ wl_on_reg: wl_on_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "wl-on-regulator"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ pinctrl-0 = <&wl_on_pins>; -+ pinctrl-names = "default"; -+ -+ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; -+ -+ startup-delay-us = <150000>; -+ enable-active-high; -+ }; -+ -+ clocks: clocks { -+ }; -+ -+ cam1_clk: cam1_clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ cam0_clk: cam0_clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ cam0_reg: cam0_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "cam0_reg"; -+ enable-active-high; -+ status = "okay"; -+ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector -+ }; -+ -+ cam1_reg: cam1_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "cam1_reg"; -+ enable-active-high; -+ status = "okay"; -+ gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector -+ }; -+ -+ cam_dummy_reg: cam_dummy_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "cam-dummy-reg"; -+ status = "okay"; -+ }; -+ -+ dummy: dummy { -+ // A target for unwanted overlay fragments -+ }; -+ -+ -+ // A few extra labels to keep overlays happy -+ -+ i2c0if: i2c0if {}; -+ i2c0mux: i2c0mux {}; -+}; -+ -+rp1_target: &pcie2 { -+ brcm,enable-mps-rcb; -+ brcm,vdm-qos-map = <0xbbaa9888>; -+ aspm-no-l0s; -+ status = "okay"; -+}; -+ -+// Add some labels to 2712 device -+ -+// The system UART -+uart10: &_uart0 { status = "okay"; }; -+ -+// The system SPI for the bootloader EEPROM -+spi10: &_spi0 { status = "okay"; }; -+ -+i2c_rp1boot: &_i2c3 { }; -+ -+#include "rp1.dtsi" -+ -+&rp1 { -+ // PCIe address space layout: -+ // 00_00000000-00_00xxxxxx = RP1 peripherals -+ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM -+ -+ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx -+ // This is the RP1 peripheral space -+ ranges = <0xc0 0x40000000 -+ 0x02000000 0x00 0x00000000 -+ 0x00 0x00400000>; -+ -+ dma-ranges = -+ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx -+ <0x10 0x00000000 -+ 0x43000000 0x10 0x00000000 -+ 0x10 0x00000000>, -+ -+ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx -+ // This allows the RP1 DMA controller to address RP1 hardware -+ <0xc0 0x40000000 -+ 0x02000000 0x0 0x00000000 -+ 0x0 0x00400000>, -+ -+ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx -+ <0x00 0x00000000 -+ 0x02000000 0x10 0x00000000 -+ 0x10 0x00000000>; -+}; -+ -+// Expose RP1 nodes as system nodes with labels -+ -+&rp1_dma { -+ status = "okay"; -+}; -+ -+&rp1_eth { -+ status = "okay"; -+ phy-handle = <&phy1>; -+ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; -+ phy-reset-duration = <5>; -+ -+ phy1: ethernet-phy@1 { -+ reg = <0x1>; -+ brcm,powerdown-enable; -+ }; -+}; -+ -+gpio: &rp1_gpio { -+ status = "okay"; -+}; -+ -+aux: &dummy {}; -+ -+&rp1_usb0 { -+ pinctrl-0 = <&usb_vbus_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&rp1_usb1 { -+ status = "okay"; -+}; -+ -+#include "bcm2712-rpi.dtsi" -+ -+i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only -+ pinctrl-0 = <&rp1_i2c6_38_39>; -+ pinctrl-names = "default"; -+ clock-frequency = <100000>; -+}; -+ -+i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only -+ pinctrl-0 = <&rp1_i2c4_40_41>; -+ pinctrl-names = "default"; -+ clock-frequency = <100000>; -+}; -+ -+i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility -+ -+csi0: &rp1_csi0 { }; -+csi1: &rp1_csi1 { }; -+dsi0: &rp1_dsi0 { }; -+dsi1: &rp1_dsi1 { }; -+dpi: &rp1_dpi { }; -+vec: &rp1_vec { }; -+dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; -+dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; -+dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; -+dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; -+dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; -+dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; -+dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; -+dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; -+dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; -+dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; -+ -+/* Add the IOMMUs for some RP1 bus masters */ -+ -+&csi0 { -+ iommus = <&iommu5>; -+}; -+ -+&csi1 { -+ iommus = <&iommu5>; -+}; -+ -+&dsi0 { -+ iommus = <&iommu5>; -+}; -+ -+&dsi1 { -+ iommus = <&iommu5>; -+}; -+ -+&dpi { -+ iommus = <&iommu5>; -+}; -+ -+&vec { -+ iommus = <&iommu5>; -+}; -+ -+&ddc0 { -+ status = "disabled"; -+}; -+ -+&ddc1 { -+ status = "disabled"; -+}; -+ -+&hdmi0 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ status = "disabled"; -+}; -+ -+&hdmi1 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ status = "disabled"; -+}; -+ -+&hvs { -+ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; -+ clock-names = "core", "disp"; -+}; -+ -+&mop { -+ status = "disabled"; -+}; -+ -+&moplet { -+ status = "disabled"; -+}; -+ -+&pixelvalve0 { -+ status = "disabled"; -+}; -+ -+&pixelvalve1 { -+ status = "disabled"; -+}; -+ -+&disp_intr { -+ status = "disabled"; -+}; -+ -+/* SDIO1 is used to drive the SD card */ -+&sdio1 { -+ pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>; -+ pinctrl-names = "default"; -+ vqmmc-supply = <&sd_io_1v8_reg>; -+ vmmc-supply = <&sd_vcc_reg>; -+ bus-width = <4>; -+ sd-uhs-sdr50; -+ sd-uhs-ddr50; -+ sd-uhs-sdr104; -+ cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>; -+ //no-1-8-v; -+ status = "okay"; -+}; -+ -+&pinctrl_aon { -+ emmc_aon_cd_pins: emmc_aon_cd_pins { -+ function = "sd_card_g"; -+ pins = "aon_gpio5"; -+ bias-pull-up; -+ }; -+ -+ /* Slight hack - only one PWM pin (status LED) is usable */ -+ aon_pwm_1pin: aon_pwm_1pin { -+ function = "aon_pwm"; -+ pins = "aon_gpio9"; -+ }; -+}; -+ -+&pinctrl { -+ pwr_button_pins: pwr_button_pins { -+ function = "gpio"; -+ pins = "gpio20"; -+ bias-pull-up; -+ }; -+ -+ wl_on_pins: wl_on_pins { -+ function = "gpio"; -+ pins = "gpio28"; -+ }; -+ -+ bt_shutdown_pins: bt_shutdown_pins { -+ function = "gpio"; -+ pins = "gpio29"; -+ }; -+ -+ emmc_sd_pulls: emmc_sd_pulls { -+ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3"; -+ bias-pull-up; -+ }; -+}; -+ -+/* uarta communicates with the BT module */ -+&uarta { -+ uart-has-rtscts; -+ auto-flow-control; -+ status = "okay"; -+ clock-frequency = <96000000>; -+ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; -+ pinctrl-names = "default"; -+ -+ bluetooth: bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <3000000>; -+ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; -+ local-bd-address = [ 00 00 00 00 00 00 ]; -+ }; -+}; -+ -+&i2c_rp1boot { -+ clock-frequency = <400000>; -+ pinctrl-0 = <&i2c3_m4_agpio0_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/ { -+ chosen: chosen { -+ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; -+ stdout-path = "serial10:115200n8"; -+ }; -+ -+ fan: cooling_fan { -+ status = "disabled"; -+ compatible = "pwm-fan"; -+ #cooling-cells = <2>; -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ cooling-levels = <0 75 125 175 250>; -+ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; -+ rpm-regmap = <&rp1_pwm1>; -+ rpm-offset = <0x3c>; -+ }; -+ -+ pwr_button { -+ compatible = "gpio-keys"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_button_pins>; -+ status = "okay"; -+ -+ pwr_key: pwr { -+ label = "pwr_button"; -+ // linux,code = <205>; // KEY_SUSPEND -+ linux,code = <116>; // KEY_POWER -+ gpios = <&gio 20 GPIO_ACTIVE_LOW>; -+ debounce-interval = <50>; // ms -+ }; -+ }; -+}; -+ -+&usb { -+ power-domains = <&power RPI_POWER_DOMAIN_USB>; -+}; -+ -+/* SDIO2 drives the WLAN interface */ -+&sdio2 { -+ pinctrl-0 = <&sdio2_30_pins>; -+ pinctrl-names = "default"; -+ bus-width = <4>; -+ vmmc-supply = <&wl_on_reg>; -+ sd-uhs-ddr50; -+ non-removable; -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ wifi: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ local-mac-address = [00 00 00 00 00 00]; -+ }; -+}; -+ -+&rpivid { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ spi10_gpio2: spi10_gpio2 { -+ function = "vc_spi0"; -+ pins = "gpio2", "gpio3", "gpio4"; -+ bias-disable; -+ }; -+ -+ spi10_cs_gpio1: spi10_cs_gpio1 { -+ function = "gpio"; -+ pins = "gpio1"; -+ bias-pull-up; -+ }; -+}; -+ -+spi10_pins: &spi10_gpio2 {}; -+spi10_cs_pins: &spi10_cs_gpio1 {}; -+ -+&spi10 { -+ pinctrl-names = "default"; -+ cs-gpios = <&gio 1 1>; -+ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; -+ -+ spidev10: spidev@0 { -+ compatible = "spidev"; -+ reg = <0>; /* CE0 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <20000000>; -+ status = "okay"; -+ }; -+}; -+ -+// ============================================= -+// Board specific stuff here -+ -+&gio_aon { -+ // Don't use GIO_AON as an interrupt controller because it will -+ // clash with the firmware monitoring the PMIC interrupt via the VPU. -+ -+ /delete-property/ interrupt-controller; -+}; -+ -+&main_aon_irq { -+ // Don't use the MAIN_AON_IRQ interrupt controller because it will -+ // clash with the firmware monitoring the PMIC interrupt via the VPU. -+ -+ status = "disabled"; -+}; -+ -+&rp1_pwm1 { -+ status = "disabled"; -+ pinctrl-0 = <&rp1_pwm1_gpio45>; -+ pinctrl-names = "default"; -+}; -+ -+&thermal_trips { -+ cpu_tepid: cpu-tepid { -+ temperature = <50000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_warm: cpu-warm { -+ temperature = <60000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_hot: cpu-hot { -+ temperature = <67500>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_vhot: cpu-vhot { -+ temperature = <75000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+}; -+ -+&cooling_maps { -+ tepid { -+ trip = <&cpu_tepid>; -+ cooling-device = <&fan 1 1>; -+ }; -+ -+ warm { -+ trip = <&cpu_warm>; -+ cooling-device = <&fan 2 2>; -+ }; -+ -+ hot { -+ trip = <&cpu_hot>; -+ cooling-device = <&fan 3 3>; -+ }; -+ -+ vhot { -+ trip = <&cpu_vhot>; -+ cooling-device = <&fan 4 4>; -+ }; -+ -+ melt { -+ trip = <&cpu_crit>; -+ cooling-device = <&fan 4 4>; -+ }; -+}; -+ -+&gio { -+ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank -+ // to reduce the clutter in gpioinfo/pinctrl -+ brcm,gpio-bank-widths = <32 4>; -+ -+ gpio-line-names = -+ "-", // GPIO_000 -+ "2712_BOOT_CS_N", // GPIO_001 -+ "2712_BOOT_MISO", // GPIO_002 -+ "2712_BOOT_MOSI", // GPIO_003 -+ "2712_BOOT_SCLK", // GPIO_004 -+ "-", // GPIO_005 -+ "-", // GPIO_006 -+ "-", // GPIO_007 -+ "-", // GPIO_008 -+ "-", // GPIO_009 -+ "-", // GPIO_010 -+ "-", // GPIO_011 -+ "-", // GPIO_012 -+ "-", // GPIO_013 -+ "PCIE_SDA", // GPIO_014 -+ "PCIE_SCL", // GPIO_015 -+ "-", // GPIO_016 -+ "-", // GPIO_017 -+ "-", // GPIO_018 -+ "-", // GPIO_019 -+ "PWR_GPIO", // GPIO_020 -+ "2712_G21_FS", // GPIO_021 -+ "-", // GPIO_022 -+ "-", // GPIO_023 -+ "BT_RTS", // GPIO_024 -+ "BT_CTS", // GPIO_025 -+ "BT_TXD", // GPIO_026 -+ "BT_RXD", // GPIO_027 -+ "WL_ON", // GPIO_028 -+ "BT_ON", // GPIO_029 -+ "WIFI_SDIO_CLK", // GPIO_030 -+ "WIFI_SDIO_CMD", // GPIO_031 -+ "WIFI_SDIO_D0", // GPIO_032 -+ "WIFI_SDIO_D1", // GPIO_033 -+ "WIFI_SDIO_D2", // GPIO_034 -+ "WIFI_SDIO_D3"; // GPIO_035 -+}; -+ -+&gio_aon { -+ gpio-line-names = -+ "RP1_SDA", // AON_GPIO_00 -+ "RP1_SCL", // AON_GPIO_01 -+ "RP1_RUN", // AON_GPIO_02 -+ "SD_IOVDD_SEL", // AON_GPIO_03 -+ "SD_PWR_ON", // AON_GPIO_04 -+ "SD_CDET_N", // AON_GPIO_05 -+ "SD_FLG_N", // AON_GPIO_06 -+ "-", // AON_GPIO_07 -+ "2712_WAKE", // AON_GPIO_08 -+ "2712_STAT_LED", // AON_GPIO_09 -+ "-", // AON_GPIO_10 -+ "-", // AON_GPIO_11 -+ "PMIC_INT", // AON_GPIO_12 -+ "UART_TX_FS", // AON_GPIO_13 -+ "UART_RX_FS", // AON_GPIO_14 -+ "-", // AON_GPIO_15 -+ "-", // AON_GPIO_16 -+ -+ // Pad bank0 out to 32 entries -+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", -+ -+ "HDMI0_SCL", // AON_SGPIO_00 -+ "HDMI0_SDA", // AON_SGPIO_01 -+ "HDMI1_SCL", // AON_SGPIO_02 -+ "HDMI1_SDA", // AON_SGPIO_03 -+ "PMIC_SCL", // AON_SGPIO_04 -+ "PMIC_SDA"; // AON_SGPIO_05 -+ -+ rp1_run_hog { -+ gpio-hog; -+ gpios = <2 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "RP1 RUN pin"; -+ }; -+}; -+ -+&rp1_gpio { -+ gpio-line-names = -+ "ID_SDA", // GPIO0 -+ "ID_SCL", // GPIO1 -+ "GPIO2", // GPIO2 -+ "GPIO3", // GPIO3 -+ "GPIO4", // GPIO4 -+ "GPIO5", // GPIO5 -+ "GPIO6", // GPIO6 -+ "GPIO7", // GPIO7 -+ "GPIO8", // GPIO8 -+ "GPIO9", // GPIO9 -+ "GPIO10", // GPIO10 -+ "GPIO11", // GPIO11 -+ "GPIO12", // GPIO12 -+ "GPIO13", // GPIO13 -+ "GPIO14", // GPIO14 -+ "GPIO15", // GPIO15 -+ "GPIO16", // GPIO16 -+ "GPIO17", // GPIO17 -+ "GPIO18", // GPIO18 -+ "GPIO19", // GPIO19 -+ "GPIO20", // GPIO20 -+ "GPIO21", // GPIO21 -+ "GPIO22", // GPIO22 -+ "GPIO23", // GPIO23 -+ "GPIO24", // GPIO24 -+ "GPIO25", // GPIO25 -+ "GPIO26", // GPIO26 -+ "GPIO27", // GPIO27 -+ -+ "PCIE_RP1_WAKE", // GPIO28 -+ "FAN_TACH", // GPIO29 -+ "HOST_SDA", // GPIO30 -+ "HOST_SCL", // GPIO31 -+ "ETH_RST_N", // GPIO32 -+ "-", // GPIO33 -+ -+ "CD0_IO0_MICCLK", // GPIO34 -+ "CD0_IO0_MICDAT0", // GPIO35 -+ "RP1_PCIE_CLKREQ_N", // GPIO36 -+ "-", // GPIO37 -+ "CD0_SDA", // GPIO38 -+ "CD0_SCL", // GPIO39 -+ "CD1_SDA", // GPIO40 -+ "CD1_SCL", // GPIO41 -+ "USB_VBUS_EN", // GPIO42 -+ "USB_OC_N", // GPIO43 -+ "RP1_STAT_LED", // GPIO44 -+ "FAN_PWM", // GPIO45 -+ "CD1_IO0_MICCLK", // GPIO46 -+ "2712_WAKE", // GPIO47 -+ "CD1_IO1_MICDAT1", // GPIO48 -+ "EN_MAX_USB_CUR", // GPIO49 -+ "-", // GPIO50 -+ "-", // GPIO51 -+ "-", // GPIO52 -+ "-"; // GPIO53 -+ -+ usb_vbus_pins: usb_vbus_pins { -+ function = "vbus1"; -+ pins = "gpio42", "gpio43"; -+ }; -+}; -+ -+/ { -+ aliases: aliases { -+ blconfig = &blconfig; -+ blpubkey = &blpubkey; -+ bluetooth = &bluetooth; -+ console = &uart10; -+ ethernet0 = &rp1_eth; -+ wifi0 = &wifi; -+ fb = &fb; -+ mailbox = &mailbox; -+ mmc0 = &sdio1; -+ uart0 = &uart0; -+ uart1 = &uart1; -+ uart2 = &uart2; -+ uart3 = &uart3; -+ uart4 = &uart4; -+ uart10 = &uart10; -+ serial0 = &uart0; -+ serial1 = &uart1; -+ serial2 = &uart2; -+ serial3 = &uart3; -+ serial4 = &uart4; -+ serial10 = &uart10; -+ i2c = &i2c_arm; -+ i2c0 = &i2c0; -+ i2c1 = &i2c1; -+ i2c2 = &i2c2; -+ i2c3 = &i2c3; -+ i2c4 = &i2c4; -+ i2c5 = &i2c5; -+ i2c6 = &i2c6; -+ i2c10 = &i2c_rp1boot; -+ // Bit-bashed i2c_gpios start at 10 -+ spi0 = &spi0; -+ spi1 = &spi1; -+ spi2 = &spi2; -+ spi3 = &spi3; -+ spi4 = &spi4; -+ spi5 = &spi5; -+ spi10 = &spi10; -+ gpio0 = &gpio; -+ gpio1 = &gio; -+ gpio2 = &gio_aon; -+ gpio3 = &pinctrl; -+ gpio4 = &pinctrl_aon; -+ usb0 = &rp1_usb0; -+ usb1 = &rp1_usb1; -+ drm-dsi1 = &dsi0; -+ drm-dsi2 = &dsi1; -+ }; -+ -+ __overrides__ { -+ bdaddr = <&bluetooth>, "local-bd-address["; -+ button_debounce = <&pwr_key>, "debounce-interval:0"; -+ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; -+ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; -+ i2c0 = <&i2c0>, "status"; -+ i2c1 = <&i2c1>, "status"; -+ i2c = <&i2c1>, "status"; -+ i2c_arm = <&i2c_arm>, "status"; -+ i2c_vc = <&i2c_vc>, "status"; -+ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; -+ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; -+ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; -+ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; -+ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; -+ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; -+ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; -+ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; -+ krnbt = <&bluetooth>, "status"; -+ nvme = <&pciex1>, "status"; -+ pciex1 = <&pciex1>, "status"; -+ pciex1_gen = <&pciex1> , "max-link-speed:0"; -+ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; -+ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; -+ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; -+ random = <&random>, "status"; -+ rtc = <&rpi_rtc>, "status"; -+ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; -+ sd_cqe = <&sdio1>, "supports-cqe?"; -+ spi = <&spi0>, "status"; -+ suspend = <&pwr_key>, "linux,code:0=205"; -+ uart0 = <&uart0>, "status"; -+ wifiaddr = <&wifi>, "local-mac-address["; -+ -+ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>; -+ act_led_activelow = <&led_act>,"gpios:8"; -+ act_led_trigger = <&led_act>, "linux,default-trigger"; -+ pwr_led_gpio = <&led_pwr>,"gpios:4"; -+ pwr_led_activelow = <&led_pwr>, "gpios:8"; -+ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; -+ eth_led0 = <&phy1>,"led-modes:0"; -+ eth_led1 = <&phy1>,"led-modes:4"; -+ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; -+ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; -+ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; -+ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; -+ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; -+ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; -+ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; -+ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; -+ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; -+ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; -+ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; -+ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; -+ -+ fan_temp0 = <&cpu_tepid>,"temperature:0"; -+ fan_temp1 = <&cpu_warm>,"temperature:0"; -+ fan_temp2 = <&cpu_hot>,"temperature:0"; -+ fan_temp3 = <&cpu_vhot>,"temperature:0"; -+ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; -+ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; -+ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; -+ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; -+ fan_temp0_speed = <&fan>, "cooling-levels:4"; -+ fan_temp1_speed = <&fan>, "cooling-levels:8"; -+ fan_temp2_speed = <&fan>, "cooling-levels:12"; -+ fan_temp3_speed = <&fan>, "cooling-levels:16"; -+ }; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts -new file mode 100644 -index 000000000000..f89321921f27 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts -@@ -0,0 +1,20 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/dts-v1/; -+ -+#include "bcm2712-rpi-cm5.dtsi" -+ -+// The RP1 USB3 interfaces are not usable on CM4IO -+ -+&rp1_usb0 { -+ status = "disabled"; -+}; -+ -+&rp1_usb1 { -+ status = "disabled"; -+}; -+ -+/ { -+ __overrides__ { -+ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; -+ }; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts -new file mode 100644 -index 000000000000..47ce4ff5049a ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts -@@ -0,0 +1,10 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/dts-v1/; -+ -+#include "bcm2712-rpi-cm5.dtsi" -+ -+/ { -+ __overrides__ { -+ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; -+ }; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi -new file mode 100644 -index 000000000000..b90d24a40bc1 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi -@@ -0,0 +1,888 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define i2c0 _i2c0 -+#define i2c3 _i2c3 -+#define i2c4 _i2c4 -+#define i2c5 _i2c5 -+#define i2c6 _i2c6 -+#define i2c8 _i2c8 -+#define i2s _i2s -+#define pwm0 _pwm0 -+#define pwm1 _pwm1 -+#define spi0 _spi0 -+#define spi3 _spi3 -+#define spi4 _spi4 -+#define spi5 _spi5 -+#define spi6 _spi6 -+#define uart0 _uart0 -+#define uart2 _uart2 -+#define uart5 _uart5 -+ -+#include "bcm2712.dtsi" -+ -+#undef i2c0 -+#undef i2c3 -+#undef i2c4 -+#undef i2c5 -+#undef i2c6 -+#undef i2c8 -+#undef i2s -+#undef pwm0 -+#undef pwm1 -+#undef spi0 -+#undef spi3 -+#undef spi4 -+#undef spi5 -+#undef spi6 -+#undef uart0 -+#undef uart2 -+#undef uart3 -+#undef uart4 -+#undef uart5 -+ -+/ { -+ compatible = "raspberrypi,5-compute-model", "brcm,bcm2712"; -+ model = "Raspberry Pi Compute Module 5"; -+ -+ /* Will be filled by the bootloader */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0 0 0x28000000>; -+ }; -+ -+ leds: leds { -+ compatible = "gpio-leds"; -+ -+ led_pwr: led-pwr { -+ label = "PWR"; -+ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ linux,default-trigger = "none"; -+ }; -+ -+ led_act: led-act { -+ label = "ACT"; -+ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; -+ default-state = "off"; -+ linux,default-trigger = "mmc0"; -+ }; -+ }; -+ -+ sd_io_1v8_reg: sd_io_1v8_reg { -+ compatible = "regulator-gpio"; -+ regulator-name = "vdd-sd-io"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ regulator-settling-time-us = <5000>; -+ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; -+ states = <1800000 0x1 -+ 3300000 0x0>; -+ status = "okay"; -+ }; -+ -+ sd_vcc_reg: sd_vcc_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc-sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ enable-active-high; -+ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+ -+ wl_on_reg: wl_on_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "wl-on-regulator"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ pinctrl-0 = <&wl_on_pins>; -+ pinctrl-names = "default"; -+ -+ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; -+ -+ startup-delay-us = <150000>; -+ enable-active-high; -+ }; -+ -+ clocks: clocks { -+ }; -+ -+ cam1_clk: cam1_clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ cam0_clk: cam0_clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ cam0_reg: cam0_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "cam0_reg"; -+ enable-active-high; -+ status = "okay"; -+ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to CAM_GPIO on connector -+ }; -+ -+ cam_dummy_reg: cam_dummy_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "cam-dummy-reg"; -+ status = "okay"; -+ }; -+ -+ dummy: dummy { -+ // A target for unwanted overlay fragments -+ }; -+ -+ -+ // A few extra labels to keep overlays happy -+ -+ i2c0if: i2c0if {}; -+ i2c0mux: i2c0mux {}; -+}; -+ -+rp1_target: &pcie2 { -+ brcm,enable-mps-rcb; -+ brcm,vdm-qos-map = <0xbbaa9888>; -+ aspm-no-l0s; -+ status = "okay"; -+}; -+ -+// Add some labels to 2712 device -+ -+// The system UART -+uart10: &_uart0 { status = "okay"; }; -+ -+// The system SPI for the bootloader EEPROM -+spi10: &_spi0 { status = "okay"; }; -+ -+i2c_rp1boot: &_i2c3 { }; -+ -+#include "rp1.dtsi" -+ -+&rp1 { -+ // PCIe address space layout: -+ // 00_00000000-00_00xxxxxx = RP1 peripherals -+ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM -+ -+ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx -+ // This is the RP1 peripheral space -+ ranges = <0xc0 0x40000000 -+ 0x02000000 0x00 0x00000000 -+ 0x00 0x00400000>; -+ -+ dma-ranges = -+ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx -+ <0x10 0x00000000 -+ 0x43000000 0x10 0x00000000 -+ 0x10 0x00000000>, -+ -+ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx -+ // This allows the RP1 DMA controller to address RP1 hardware -+ <0xc0 0x40000000 -+ 0x02000000 0x0 0x00000000 -+ 0x0 0x00400000>, -+ -+ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx -+ <0x00 0x00000000 -+ 0x02000000 0x10 0x00000000 -+ 0x10 0x00000000>; -+}; -+ -+// Expose RP1 nodes as system nodes with labels -+ -+&rp1_dma { -+ status = "okay"; -+}; -+ -+&rp1_eth { -+ status = "okay"; -+ phy-handle = <&phy1>; -+ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; -+ phy-reset-duration = <5>; -+ -+ phy1: ethernet-phy@1 { -+ reg = <0x1>; -+ brcm,powerdown-enable; -+ interrupt-parent = <&gpio>; -+ interrupts = <37 IRQ_TYPE_LEVEL_LOW>; -+ }; -+}; -+ -+gpio: &rp1_gpio { -+ status = "okay"; -+}; -+ -+aux: &dummy {}; -+ -+&rp1_usb0 { -+ pinctrl-0 = <&usb_vbus_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&rp1_usb1 { -+ status = "okay"; -+}; -+ -+#include "bcm2712-rpi.dtsi" -+ -+i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only -+ pinctrl-0 = <&rp1_i2c6_38_39>; -+ pinctrl-names = "default"; -+ clock-frequency = <100000>; -+}; -+ -+i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector -+}; -+ -+i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility -+ -+cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg -+}; -+ -+csi0: &rp1_csi0 { }; -+csi1: &rp1_csi1 { }; -+dsi0: &rp1_dsi0 { }; -+dsi1: &rp1_dsi1 { }; -+dpi: &rp1_dpi { }; -+vec: &rp1_vec { }; -+dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; -+dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; -+dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; -+dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; -+dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; -+dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; -+dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; -+dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; -+dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; -+dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; -+ -+/* Add the IOMMUs for some RP1 bus masters */ -+ -+&csi0 { -+ iommus = <&iommu5>; -+}; -+ -+&csi1 { -+ iommus = <&iommu5>; -+}; -+ -+&dsi0 { -+ iommus = <&iommu5>; -+}; -+ -+&dsi1 { -+ iommus = <&iommu5>; -+}; -+ -+&dpi { -+ iommus = <&iommu5>; -+}; -+ -+&vec { -+ iommus = <&iommu5>; -+}; -+ -+&ddc0 { -+ status = "disabled"; -+}; -+ -+&ddc1 { -+ status = "disabled"; -+}; -+ -+&hdmi0 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ status = "disabled"; -+}; -+ -+&hdmi1 { -+ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; -+ clock-names = "hdmi", "bvb", "audio", "cec"; -+ status = "disabled"; -+}; -+ -+&hvs { -+ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; -+ clock-names = "core", "disp"; -+}; -+ -+&mop { -+ status = "disabled"; -+}; -+ -+&moplet { -+ status = "disabled"; -+}; -+ -+&pixelvalve0 { -+ status = "disabled"; -+}; -+ -+&pixelvalve1 { -+ status = "disabled"; -+}; -+ -+&disp_intr { -+ status = "disabled"; -+}; -+ -+/* SDIO1 is used to drive the eMMC/SD card */ -+&sdio1 { -+ pinctrl-0 = <&emmc_cmddat_pulls>, <&emmc_ds_pull>; -+ pinctrl-names = "default"; -+ vqmmc-supply = <&sd_io_1v8_reg>; -+ vmmc-supply = <&sd_vcc_reg>; -+ bus-width = <8>; -+ sd-uhs-sdr50; -+ sd-uhs-ddr50; -+ sd-uhs-sdr104; -+ mmc-hs200-1_8v; -+ broken-cd; -+ supports-cqe; -+ status = "okay"; -+}; -+ -+&pinctrl_aon { -+ ant_pins: ant_pins { -+ function = "gpio"; -+ pins = "aon_gpio5", "aon_gpio6"; -+ }; -+ -+ /* Slight hack - only one PWM pin (status LED) is usable */ -+ aon_pwm_1pin: aon_pwm_1pin { -+ function = "aon_pwm"; -+ pins = "aon_gpio9"; -+ }; -+}; -+ -+&pinctrl { -+ pwr_button_pins: pwr_button_pins { -+ function = "gpio"; -+ pins = "gpio20"; -+ bias-pull-up; -+ }; -+ -+ wl_on_pins: wl_on_pins { -+ function = "gpio"; -+ pins = "gpio28"; -+ }; -+ -+ bt_shutdown_pins: bt_shutdown_pins { -+ function = "gpio"; -+ pins = "gpio29"; -+ }; -+ -+ emmc_ds_pull: emmc_ds_pull { -+ pins = "emmc_ds"; -+ bias-pull-down; -+ }; -+ -+ emmc_cmddat_pulls: emmc_cmddat_pulls { -+ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3", -+ "emmc_dat4", "emmc_dat5", "emmc_dat6", "emmc_dat7"; -+ bias-pull-up; -+ }; -+}; -+ -+/* uarta communicates with the BT module */ -+&uarta { -+ uart-has-rtscts; -+ auto-flow-control; -+ status = "okay"; -+ clock-frequency = <96000000>; -+ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; -+ pinctrl-names = "default"; -+ -+ bluetooth: bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <3000000>; -+ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; -+ local-bd-address = [ 00 00 00 00 00 00 ]; -+ }; -+}; -+ -+&i2c_rp1boot { -+ clock-frequency = <400000>; -+ pinctrl-0 = <&i2c3_m4_agpio0_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/ { -+ chosen: chosen { -+ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe"; -+ stdout-path = "serial10:115200n8"; -+ }; -+ -+ fan: cooling_fan { -+ status = "disabled"; -+ compatible = "pwm-fan"; -+ #cooling-cells = <2>; -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ cooling-levels = <0 75 125 175 250>; -+ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; -+ rpm-regmap = <&rp1_pwm1>; -+ rpm-offset = <0x3c>; -+ }; -+ -+ pwr_button { -+ compatible = "gpio-keys"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_button_pins>; -+ status = "okay"; -+ -+ pwr_key: pwr { -+ label = "pwr_button"; -+ // linux,code = <205>; // KEY_SUSPEND -+ linux,code = <116>; // KEY_POWER -+ gpios = <&gio 20 GPIO_ACTIVE_LOW>; -+ debounce-interval = <50>; // ms -+ }; -+ }; -+}; -+ -+&usb { -+ power-domains = <&power RPI_POWER_DOMAIN_USB>; -+}; -+ -+/* SDIO2 drives the WLAN interface */ -+&sdio2 { -+ pinctrl-0 = <&sdio2_30_pins>, <&ant_pins>; -+ pinctrl-names = "default"; -+ bus-width = <4>; -+ vmmc-supply = <&wl_on_reg>; -+ sd-uhs-ddr50; -+ non-removable; -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ wifi: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ local-mac-address = [00 00 00 00 00 00]; -+ }; -+}; -+ -+&rpivid { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ spi10_gpio2: spi10_gpio2 { -+ function = "vc_spi0"; -+ pins = "gpio2", "gpio3", "gpio4"; -+ bias-disable; -+ }; -+ -+ spi10_cs_gpio1: spi10_cs_gpio1 { -+ function = "gpio"; -+ pins = "gpio1"; -+ bias-pull-up; -+ }; -+}; -+ -+spi10_pins: &spi10_gpio2 {}; -+spi10_cs_pins: &spi10_cs_gpio1 {}; -+ -+&spi10 { -+ pinctrl-names = "default"; -+ cs-gpios = <&gio 1 1>; -+ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; -+ -+ spidev10: spidev@0 { -+ compatible = "spidev"; -+ reg = <0>; /* CE0 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <20000000>; -+ status = "okay"; -+ }; -+}; -+ -+// ============================================= -+// Board specific stuff here -+ -+&gio_aon { -+ // Don't use GIO_AON as an interrupt controller because it will -+ // clash with the firmware monitoring the PMIC interrupt via the VPU. -+ -+ /delete-property/ interrupt-controller; -+}; -+ -+&main_aon_irq { -+ // Don't use the MAIN_AON_IRQ interrupt controller because it will -+ // clash with the firmware monitoring the PMIC interrupt via the VPU. -+ -+ status = "disabled"; -+}; -+ -+&rp1_pwm1 { -+ status = "disabled"; -+ pinctrl-0 = <&rp1_pwm1_gpio45>; -+ pinctrl-names = "default"; -+}; -+ -+&thermal_trips { -+ cpu_tepid: cpu-tepid { -+ temperature = <50000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_warm: cpu-warm { -+ temperature = <60000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_hot: cpu-hot { -+ temperature = <67500>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ cpu_vhot: cpu-vhot { -+ temperature = <75000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+}; -+ -+&cooling_maps { -+ tepid { -+ trip = <&cpu_tepid>; -+ cooling-device = <&fan 1 1>; -+ }; -+ -+ warm { -+ trip = <&cpu_warm>; -+ cooling-device = <&fan 2 2>; -+ }; -+ -+ hot { -+ trip = <&cpu_hot>; -+ cooling-device = <&fan 3 3>; -+ }; -+ -+ vhot { -+ trip = <&cpu_vhot>; -+ cooling-device = <&fan 4 4>; -+ }; -+ -+ melt { -+ trip = <&cpu_crit>; -+ cooling-device = <&fan 4 4>; -+ }; -+}; -+ -+&gio { -+ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank -+ // to reduce the clutter in gpioinfo/pinctrl -+ brcm,gpio-bank-widths = <32 4>; -+ -+ gpio-line-names = -+ "-", // GPIO_000 -+ "2712_BOOT_CS_N", // GPIO_001 -+ "2712_BOOT_MISO", // GPIO_002 -+ "2712_BOOT_MOSI", // GPIO_003 -+ "2712_BOOT_SCLK", // GPIO_004 -+ "-", // GPIO_005 -+ "-", // GPIO_006 -+ "-", // GPIO_007 -+ "-", // GPIO_008 -+ "-", // GPIO_009 -+ "-", // GPIO_010 -+ "-", // GPIO_011 -+ "-", // GPIO_012 -+ "-", // GPIO_013 -+ "-", // GPIO_014 -+ "-", // GPIO_015 -+ "-", // GPIO_016 -+ "-", // GPIO_017 -+ "-", // GPIO_018 -+ "-", // GPIO_019 -+ "PWR_GPIO", // GPIO_020 -+ "2712_G21_FS", // GPIO_021 -+ "-", // GPIO_022 -+ "-", // GPIO_023 -+ "BT_RTS", // GPIO_024 -+ "BT_CTS", // GPIO_025 -+ "BT_TXD", // GPIO_026 -+ "BT_RXD", // GPIO_027 -+ "WL_ON", // GPIO_028 -+ "BT_ON", // GPIO_029 -+ "WIFI_SDIO_CLK", // GPIO_030 -+ "WIFI_SDIO_CMD", // GPIO_031 -+ "WIFI_SDIO_D0", // GPIO_032 -+ "WIFI_SDIO_D1", // GPIO_033 -+ "WIFI_SDIO_D2", // GPIO_034 -+ "WIFI_SDIO_D3"; // GPIO_035 -+}; -+ -+&gio_aon { -+ gpio-line-names = -+ "RP1_SDA", // AON_GPIO_00 -+ "RP1_SCL", // AON_GPIO_01 -+ "RP1_RUN", // AON_GPIO_02 -+ "SD_IOVDD_SEL", // AON_GPIO_03 -+ "SD_PWR_ON", // AON_GPIO_04 -+ "ANT1", // AON_GPIO_05 -+ "ANT2", // AON_GPIO_06 -+ "-", // AON_GPIO_07 -+ "2712_WAKE", // AON_GPIO_08 -+ "2712_STAT_LED", // AON_GPIO_09 -+ "-", // AON_GPIO_10 -+ "-", // AON_GPIO_11 -+ "PMIC_INT", // AON_GPIO_12 -+ "UART_TX_FS", // AON_GPIO_13 -+ "UART_RX_FS", // AON_GPIO_14 -+ "-", // AON_GPIO_15 -+ "-", // AON_GPIO_16 -+ -+ // Pad bank0 out to 32 entries -+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", -+ -+ "HDMI0_SCL", // AON_SGPIO_00 -+ "HDMI0_SDA", // AON_SGPIO_01 -+ "HDMI1_SCL", // AON_SGPIO_02 -+ "HDMI1_SDA", // AON_SGPIO_03 -+ "PMIC_SCL", // AON_SGPIO_04 -+ "PMIC_SDA"; // AON_SGPIO_05 -+ -+ rp1_run_hog { -+ gpio-hog; -+ gpios = <2 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "RP1 RUN pin"; -+ }; -+ -+ ant1: ant1-hog { -+ gpio-hog; -+ gpios = <5 GPIO_ACTIVE_HIGH>; -+ /* internal antenna enabled */ -+ output-high; -+ line-name = "ant1"; -+ }; -+ -+ ant2: ant2-hog { -+ gpio-hog; -+ gpios = <6 GPIO_ACTIVE_HIGH>; -+ /* external antenna disabled */ -+ output-low; -+ line-name = "ant2"; -+ }; -+}; -+ -+&rp1_gpio { -+ gpio-line-names = -+ "ID_SDA", // GPIO0 -+ "ID_SCL", // GPIO1 -+ "GPIO2", // GPIO2 -+ "GPIO3", // GPIO3 -+ "GPIO4", // GPIO4 -+ "GPIO5", // GPIO5 -+ "GPIO6", // GPIO6 -+ "GPIO7", // GPIO7 -+ "GPIO8", // GPIO8 -+ "GPIO9", // GPIO9 -+ "GPIO10", // GPIO10 -+ "GPIO11", // GPIO11 -+ "GPIO12", // GPIO12 -+ "GPIO13", // GPIO13 -+ "GPIO14", // GPIO14 -+ "GPIO15", // GPIO15 -+ "GPIO16", // GPIO16 -+ "GPIO17", // GPIO17 -+ "GPIO18", // GPIO18 -+ "GPIO19", // GPIO19 -+ "GPIO20", // GPIO20 -+ "GPIO21", // GPIO21 -+ "GPIO22", // GPIO22 -+ "GPIO23", // GPIO23 -+ "GPIO24", // GPIO24 -+ "GPIO25", // GPIO25 -+ "GPIO26", // GPIO26 -+ "GPIO27", // GPIO27 -+ -+ "PCIE_PWR_EN", // GPIO28 -+ "FAN_TACH", // GPIO29 -+ "HOST_SDA", // GPIO30 -+ "HOST_SCL", // GPIO31 -+ "ETH_RST_N", // GPIO32 -+ "PCIE_DET_WAKE", // GPIO33 -+ -+ "CD0_IO0_MICCLK", // GPIO34 -+ "CD0_IO0_MICDAT0", // GPIO35 -+ "RP1_PCIE_CLKREQ_N", // GPIO36 -+ "ETH_IRQ_N", // GPIO37 -+ "SDA0", // GPIO38 -+ "SCL0", // GPIO39 -+ "-", // GPIO40 -+ "-", // GPIO41 -+ "USB_VBUS_EN", // GPIO42 -+ "USB_OC_N", // GPIO43 -+ "RP1_STAT_LED", // GPIO44 -+ "FAN_PWM", // GPIO45 -+ "-", // GPIO46 -+ "2712_WAKE", // GPIO47 -+ "-", // GPIO48 -+ "-", // GPIO49 -+ "-", // GPIO50 -+ "-", // GPIO51 -+ "-", // GPIO52 -+ "-"; // GPIO53 -+ -+ usb_vbus_pins: usb_vbus_pins { -+ function = "vbus1"; -+ pins = "gpio42", "gpio43"; -+ }; -+}; -+ -+/ { -+ aliases: aliases { -+ blconfig = &blconfig; -+ blpubkey = &blpubkey; -+ bluetooth = &bluetooth; -+ console = &uart10; -+ ethernet0 = &rp1_eth; -+ wifi0 = &wifi; -+ fb = &fb; -+ mailbox = &mailbox; -+ mmc0 = &sdio1; -+ uart0 = &uart0; -+ uart1 = &uart1; -+ uart2 = &uart2; -+ uart3 = &uart3; -+ uart4 = &uart4; -+ uart10 = &uart10; -+ serial0 = &uart0; -+ serial1 = &uart1; -+ serial2 = &uart2; -+ serial3 = &uart3; -+ serial4 = &uart4; -+ serial10 = &uart10; -+ i2c = &i2c_arm; -+ i2c0 = &i2c0; -+ i2c1 = &i2c1; -+ i2c2 = &i2c2; -+ i2c3 = &i2c3; -+ i2c4 = &i2c4; -+ i2c5 = &i2c5; -+ i2c6 = &i2c6; -+ i2c10 = &i2c_rp1boot; -+ // Bit-bashed i2c_gpios start at 10 -+ spi0 = &spi0; -+ spi1 = &spi1; -+ spi2 = &spi2; -+ spi3 = &spi3; -+ spi4 = &spi4; -+ spi5 = &spi5; -+ spi10 = &spi10; -+ gpio0 = &gpio; -+ gpio1 = &gio; -+ gpio2 = &gio_aon; -+ gpio3 = &pinctrl; -+ gpio4 = &pinctrl_aon; -+ usb0 = &rp1_usb0; -+ usb1 = &rp1_usb1; -+ drm-dsi1 = &dsi0; -+ drm-dsi2 = &dsi1; -+ }; -+ -+ __overrides__ { -+ bdaddr = <&bluetooth>, "local-bd-address["; -+ button_debounce = <&pwr_key>, "debounce-interval:0"; -+ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; -+ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; -+ i2c0 = <&i2c0>, "status"; -+ i2c1 = <&i2c1>, "status"; -+ i2c = <&i2c1>, "status"; -+ i2c_arm = <&i2c_arm>, "status"; -+ i2c_vc = <&i2c_vc>, "status"; -+ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; -+ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; -+ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; -+ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; -+ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; -+ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; -+ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; -+ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; -+ krnbt = <&bluetooth>, "status"; -+ nvme = <&pciex1>, "status"; -+ pciex1 = <&pciex1>, "status"; -+ pciex1_gen = <&pciex1> , "max-link-speed:0"; -+ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; -+ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; -+ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; -+ random = <&random>, "status"; -+ rtc = <&rpi_rtc>, "status"; -+ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; -+ spi = <&spi0>, "status"; -+ suspend = <&pwr_key>, "linux,code:0=205"; -+ uart0 = <&uart0>, "status"; -+ wifiaddr = <&wifi>, "local-mac-address["; -+ -+ act_led_activelow = <&led_act>, "active-low?"; -+ act_led_trigger = <&led_act>, "linux,default-trigger"; -+ pwr_led_activelow = <&led_pwr>, "gpios:8"; -+ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; -+ eth_led0 = <&phy1>,"led-modes:0"; -+ eth_led1 = <&phy1>,"led-modes:4"; -+ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; -+ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; -+ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; -+ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; -+ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; -+ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; -+ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; -+ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; -+ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; -+ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; -+ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; -+ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; -+ -+ ant1 = <&ant1>,"output-high?=on", -+ <&ant1>, "output-low?=off", -+ <&ant2>, "output-high?=off", -+ <&ant2>, "output-low?=on"; -+ ant2 = <&ant1>,"output-high?=off", -+ <&ant1>, "output-low?=on", -+ <&ant2>, "output-high?=on", -+ <&ant2>, "output-low?=off"; -+ noant = <&ant1>,"output-high?=off", -+ <&ant1>, "output-low?=on", -+ <&ant2>, "output-high?=off", -+ <&ant2>, "output-low?=on"; -+ -+ fan_temp0 = <&cpu_tepid>,"temperature:0"; -+ fan_temp1 = <&cpu_warm>,"temperature:0"; -+ fan_temp2 = <&cpu_hot>,"temperature:0"; -+ fan_temp3 = <&cpu_vhot>,"temperature:0"; -+ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; -+ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; -+ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; -+ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; -+ fan_temp0_speed = <&fan>, "cooling-levels:4"; -+ fan_temp1_speed = <&fan>, "cooling-levels:8"; -+ fan_temp2_speed = <&fan>, "cooling-levels:12"; -+ fan_temp3_speed = <&fan>, "cooling-levels:16"; -+ }; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi -new file mode 100644 -index 000000000000..f88de824e9d7 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712-rpi.dtsi -@@ -0,0 +1,337 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+ -+&soc { -+ firmware: firmware { -+ compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ mboxes = <&mailbox>; -+ dma-ranges; -+ -+ firmware_clocks: clocks { -+ compatible = "raspberrypi,firmware-clocks"; -+ #clock-cells = <1>; -+ }; -+ -+ reset: reset { -+ compatible = "raspberrypi,firmware-reset"; -+ #reset-cells = <1>; -+ }; -+ -+ vcio: vcio { -+ compatible = "raspberrypi,vcio"; -+ }; -+ }; -+ -+ power: power { -+ compatible = "raspberrypi,bcm2835-power"; -+ firmware = <&firmware>; -+ #power-domain-cells = <1>; -+ }; -+ -+ fb: fb { -+ compatible = "brcm,bcm2708-fb"; -+ firmware = <&firmware>; -+ status = "okay"; -+ }; -+ -+ rpi_rtc: rpi_rtc { -+ compatible = "raspberrypi,rpi-rtc"; -+ firmware = <&firmware>; -+ status = "okay"; -+ trickle-charge-microvolt = <0>; -+ }; -+ -+ nvmem_otp: nvmem_otp { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <0 192>; -+ status = "okay"; -+ }; -+ -+ nvmem_cust: nvmem_cust { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <1 8>; -+ status = "okay"; -+ }; -+ -+ nvmem_mac: nvmem_mac { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <2 6>; -+ status = "okay"; -+ }; -+ -+ nvmem_priv: nvmem_priv { -+ compatible = "raspberrypi,rpi-otp"; -+ firmware = <&firmware>; -+ reg = <3 16>; -+ status = "okay"; -+ }; -+ -+ /* Define these notional regulators for use by overlays, etc. */ -+ vdd_3v3_reg: fixedregulator_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-always-on; -+ regulator-max-microvolt = <3300000>; -+ regulator-min-microvolt = <3300000>; -+ regulator-name = "3v3"; -+ }; -+ -+ vdd_5v0_reg: fixedregulator_5v0 { -+ compatible = "regulator-fixed"; -+ regulator-always-on; -+ regulator-max-microvolt = <5000000>; -+ regulator-min-microvolt = <5000000>; -+ regulator-name = "5v0"; -+ }; -+}; -+ -+/ { -+ __overrides__ { -+ arm_freq; -+ axiperf = <&axiperf>,"status"; -+ -+ nvmem_cust_rw = <&nvmem_cust>,"rw?"; -+ nvmem_priv_rw = <&nvmem_priv>,"rw?"; -+ nvmem_mac_rw = <&nvmem_mac>,"rw?"; -+ strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n"; -+ }; -+}; -+ -+pciex1: &pcie1 { }; -+pciex4: &pcie2 { }; -+ -+&dma32 { -+ /* The VPU firmware uses DMA channel 11 for VCHIQ */ -+ brcm,dma-channel-mask = <0x03f>; -+}; -+ -+&dma40 { -+ /* The VPU firmware DMA channel 11 for VCHIQ */ -+ brcm,dma-channel-mask = <0x07c0>; -+}; -+ -+&hdmi0 { -+ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; -+}; -+ -+&hdmi1 { -+ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; -+}; -+ -+&spi10 { -+ dmas = <&dma40 6>, <&dma40 7>; -+ dma-names = "tx", "rx"; -+}; -+ -+&usb { -+ power-domains = <&power RPI_POWER_DOMAIN_USB>; -+}; -+ -+&rmem { -+ /* -+ * RPi5's co-processor will copy the board's bootloader configuration -+ * into memory for the OS to consume. It'll also update this node with -+ * its placement information. -+ */ -+ blconfig: nvram@0 { -+ compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ reg = <0x0 0x0 0x0>; -+ no-map; -+ status = "disabled"; -+ }; -+ /* -+ * RPi5 will copy the binary public key blob (if present) from the bootloader -+ * into memory for use by the OS. -+ */ -+ blpubkey: nvram@1 { -+ compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ reg = <0x0 0x0 0x0>; -+ no-map; -+ status = "disabled"; -+ }; -+}; -+ -+&rp1_adc { -+ status = "okay"; -+}; -+ -+/* Add some gpiomem nodes to make the devices accessible to userspace. -+ * /dev/gpiomem should expose the registers for the interface with DT alias -+ * gpio. -+ */ -+ -+&rp1 { -+ gpiomem@d0000 { -+ /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */ -+ compatible = "raspberrypi,gpiomem"; -+ reg = <0xc0 0x400d0000 0x0 0x30000>; -+ chardev-name = "gpiomem0"; -+ }; -+}; -+ -+&soc { -+ gpiomem@7d508500 { -+ compatible = "raspberrypi,gpiomem"; -+ reg = <0x7d508500 0x40>; -+ chardev-name = "gpiomem1"; -+ }; -+ -+ gpiomem@7d517c00 { -+ compatible = "raspberrypi,gpiomem"; -+ reg = <0x7d517c00 0x40>; -+ chardev-name = "gpiomem2"; -+ }; -+ -+ gpiomem@7d504100 { -+ compatible = "raspberrypi,gpiomem"; -+ reg = <0x7d504100 0x20>; -+ chardev-name = "gpiomem3"; -+ }; -+ -+ gpiomem@7d510700 { -+ compatible = "raspberrypi,gpiomem"; -+ reg = <0x7d510700 0x20>; -+ chardev-name = "gpiomem4"; -+ }; -+ -+ sound: sound { -+ status = "disabled"; -+ }; -+}; -+ -+i2c0: &rp1_i2c0 { }; -+i2c1: &rp1_i2c1 { }; -+i2c2: &rp1_i2c2 { }; -+i2c3: &rp1_i2c3 { }; -+i2c4: &rp1_i2c4 { }; -+i2c5: &rp1_i2c5 { }; -+i2c6: &rp1_i2c6 { }; -+i2s: &rp1_i2s0 { }; -+i2s_clk_producer: &rp1_i2s0 { }; -+i2s_clk_consumer: &rp1_i2s1 { }; -+pwm0: &rp1_pwm0 { }; -+pwm1: &rp1_pwm1 { }; -+pwm: &pwm0 { }; -+spi0: &rp1_spi0 { }; -+spi1: &rp1_spi1 { }; -+spi2: &rp1_spi2 { }; -+spi3: &rp1_spi3 { }; -+spi4: &rp1_spi4 { }; -+spi5: &rp1_spi5 { }; -+ -+uart0_pins: &rp1_uart0_14_15 {}; -+uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {}; -+uart0: &rp1_uart0 { -+ pinctrl-0 = <&uart0_pins>; -+}; -+ -+uart1_pins: &rp1_uart1_0_1 {}; -+uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {}; -+uart1: &rp1_uart1 { }; -+ -+uart2_pins: &rp1_uart2_4_5 {}; -+uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {}; -+uart2: &rp1_uart2 { }; -+ -+uart3_pins: &rp1_uart3_8_9 {}; -+uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {}; -+uart3: &rp1_uart3 { }; -+ -+uart4_pins: &rp1_uart4_12_13 {}; -+uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {}; -+uart4: &rp1_uart4 { }; -+ -+i2c0_pins: &rp1_i2c0_0_1 {}; -+i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI) -+ pinctrl-0 = <&i2c0_pins>; -+ pinctrl-names = "default"; -+ clock-frequency = <100000>; -+}; -+ -+i2c1_pins: &rp1_i2c1_2_3 {}; -+i2c_arm: &i2c1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c1_pins>; -+ clock-frequency = <100000>; -+}; -+ -+i2c2_pins: &rp1_i2c2_4_5 {}; -+&i2c2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c2_pins>; -+}; -+ -+i2c3_pins: &rp1_i2c3_6_7 {}; -+&i2c3 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c3_pins>; -+}; -+ -+&i2s_clk_producer { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&rp1_i2s0_18_21>; -+}; -+ -+&i2s_clk_consumer { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&rp1_i2s1_18_21>; -+}; -+ -+spi0_pins: &rp1_spi0_gpio9 {}; -+spi0_cs_pins: &rp1_spi0_cs_gpio7 {}; -+ -+&spi0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; -+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; -+ -+ spidev0: spidev@0 { -+ compatible = "spidev"; -+ reg = <0>; /* CE0 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <125000000>; -+ }; -+ -+ spidev1: spidev@1 { -+ compatible = "spidev"; -+ reg = <1>; /* CE1 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <125000000>; -+ }; -+}; -+ -+spi2_pins: &rp1_spi2_gpio1 {}; -+&spi2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi2_pins>; -+}; -+ -+spi3_pins: &rp1_spi3_gpio5 {}; -+&spi3 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi3_pins>; -+}; -+ -+spi4_pins: &rp1_spi4_gpio9 {}; -+&spi4 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi4_pins>; -+}; -+ -+spi5_pins: &rp1_spi5_gpio13 {}; -+&spi5 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi5_pins>; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712.dtsi b/arch/arm/boot/dts/broadcom/bcm2712.dtsi -new file mode 100644 -index 000000000000..ee389a9cf89b ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712.dtsi -@@ -0,0 +1,1304 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include -+#include -+#include -+ -+/ { -+ compatible = "brcm,bcm2712", "brcm,bcm2711"; -+ model = "BCM2712"; -+ -+ #address-cells = <2>; -+ #size-cells = <1>; -+ -+ interrupt-parent = <&gicv2>; -+ -+ rmem: reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <1>; -+ ranges; -+ -+ atf@0 { -+ reg = <0x0 0x0 0x80000>; -+ no-map; -+ }; -+ -+ cma: linux,cma { -+ compatible = "shared-dma-pool"; -+ size = <0x4000000>; /* 64MB */ -+ reusable; -+ linux,cma-default; -+ -+ /* -+ * arm64 reserves the CMA by default somewhere in -+ * ZONE_DMA32, that's not good enough for the BCM2711 -+ * as some devices can only address the lower 1G of -+ * memory (ZONE_DMA). -+ */ -+ alloc-ranges = <0x0 0x00000000 0x40000000>; -+ }; -+ }; -+ -+ thermal-zones { -+ cpu_thermal: cpu-thermal { -+ polling-delay-passive = <2000>; -+ polling-delay = <1000>; -+ coefficients = <(-550) 450000>; -+ thermal-sensors = <&thermal>; -+ -+ thermal_trips: trips { -+ cpu_crit: cpu-crit { -+ temperature = <110000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling_maps: cooling-maps { -+ }; -+ }; -+ }; -+ -+ clk_27MHz: clk-27M { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <27000000>; -+ clock-output-names = "27MHz-clock"; -+ }; -+ -+ clk_108MHz: clk-108M { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <108000000>; -+ clock-output-names = "108MHz-clock"; -+ }; -+ -+ hvs: hvs@107c580000 { -+ compatible = "brcm,bcm2712-hvs"; -+ reg = <0x10 0x7c580000 0x1a000>; -+ interrupt-parent = <&disp_intr>; -+ interrupts = <2>, <9>, <16>; -+ interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof"; -+ //iommus = <&iommu4>; -+ status = "disabled"; -+ }; -+ -+ soc: soc { -+ compatible = "simple-bus"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ ranges = <0x7c000000 0x10 0x7c000000 0x04000000>; -+ /* Emulate a contiguous 30-bit address range for DMA */ -+ dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>, -+ <0x7c000000 0x10 0x7c000000 0x04000000>; -+ -+ system_timer: timer@7c003000 { -+ compatible = "brcm,bcm2835-system-timer"; -+ reg = <0x7c003000 0x1000>; -+ interrupts = , -+ , -+ , -+ ; -+ clock-frequency = <1000000>; -+ }; -+ -+ firmwarekms: firmwarekms@7d503000 { -+ compatible = "raspberrypi,rpi-firmware-kms-2712"; -+ /* SUN_L2 interrupt reg */ -+ reg = <0x7d503000 0x18>; -+ interrupt-parent = <&cpu_l2_irq>; -+ interrupts = <19>; -+ brcm,firmware = <&firmware>; -+ status = "disabled"; -+ }; -+ -+ axiperf: axiperf { -+ compatible = "brcm,bcm2712-axiperf"; -+ reg = <0x7c012800 0x100>, -+ <0x7e000000 0x100>; -+ firmware = <&firmware>; -+ status = "disabled"; -+ }; -+ -+ mailbox: mailbox@7c013880 { -+ compatible = "brcm,bcm2835-mbox"; -+ reg = <0x7c013880 0x40>; -+ interrupts = ; -+ #mbox-cells = <0>; -+ }; -+ -+ pixelvalve0: pixelvalve@7c410000 { -+ compatible = "brcm,bcm2712-pixelvalve0"; -+ reg = <0x7c410000 0x100>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ pixelvalve1: pixelvalve@7c411000 { -+ compatible = "brcm,bcm2712-pixelvalve1"; -+ reg = <0x7c411000 0x100>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ mop: mop@7c500000 { -+ compatible = "brcm,bcm2712-mop"; -+ reg = <0x7c500000 0x28>; -+ interrupt-parent = <&disp_intr>; -+ interrupts = <1>; -+ status = "disabled"; -+ }; -+ -+ moplet: moplet@7c501000 { -+ compatible = "brcm,bcm2712-moplet"; -+ reg = <0x7c501000 0x20>; -+ interrupt-parent = <&disp_intr>; -+ interrupts = <0>; -+ status = "disabled"; -+ }; -+ -+ disp_intr: interrupt-controller@7c502000 { -+ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; -+ reg = <0x7c502000 0x30>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ status = "disabled"; -+ }; -+ -+ dvp: clock@7c700000 { -+ compatible = "brcm,brcm2711-dvp"; -+ reg = <0x7c700000 0x10>; -+ clocks = <&clk_108MHz>; -+ #clock-cells = <1>; -+ #reset-cells = <1>; -+ }; -+ -+ /* -+ * This node is the provider for the enable-method for -+ * bringing up secondary cores. -+ */ -+ local_intc: local_intc@7cd00000 { -+ compatible = "brcm,bcm2836-l1-intc"; -+ reg = <0x7cd00000 0x100>; -+ }; -+ -+ uart0: serial@7d001000 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7d001000 0x200>; -+ interrupts = ; -+ clocks = <&clk_uart>, -+ <&clk_vpu>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart2: serial@7d001400 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7d001400 0x200>; -+ interrupts = ; -+ clocks = <&clk_uart>, -+ <&clk_vpu>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart5: serial@7d001a00 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7d001a00 0x200>; -+ interrupts = ; -+ clocks = <&clk_uart>, -+ <&clk_vpu>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ sdhost: mmc@7d002000 { -+ compatible = "brcm,bcm2835-sdhost"; -+ reg = <0x7d002000 0x100>; -+ //interrupts = ; -+ clocks = <&clk_vpu>; -+ status = "disabled"; -+ }; -+ -+ i2s: i2s@7d003000 { -+ compatible = "brcm,bcm2835-i2s"; -+ reg = <0x7d003000 0x24>; -+ //clocks = <&cprman BCM2835_CLOCK_PCM>; -+ status = "disabled"; -+ }; -+ -+ spi0: spi@7d004000 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7d004000 0x200>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ num-cs = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi3: spi@7d004600 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7d004600 0x0200>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi4: spi@7d004800 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7d004800 0x0200>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi5: spi@7d004a00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7d004a00 0x0200>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi6: spi@7d004c00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7d004c00 0x0200>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c0: i2c@7d005000 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005000 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c3: i2c@7d005600 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005600 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c4: i2c@7d005800 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005800 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c5: i2c@7d005a00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005a00 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c6: i2c@7d005c00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005c00 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c8: i2c@7d005e00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7d005e00 0x20>; -+ interrupts = ; -+ clocks = <&clk_vpu>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ pwm0: pwm@7d00c000 { -+ compatible = "brcm,bcm2835-pwm"; -+ reg = <0x7d00c000 0x28>; -+ assigned-clock-rates = <50000000>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ -+ pwm1: pwm@7d00c800 { -+ compatible = "brcm,bcm2835-pwm"; -+ reg = <0x7d00c800 0x28>; -+ assigned-clock-rates = <50000000>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ -+ pm: watchdog@7d200000 { -+ compatible = "brcm,bcm2712-pm"; -+ reg = <0x7d200000 0x308>; -+ reg-names = "pm"; -+ #power-domain-cells = <1>; -+ #reset-cells = <1>; -+ //clocks = <&cprman BCM2835_CLOCK_V3D>, -+ // <&cprman BCM2835_CLOCK_PERI_IMAGE>, -+ // <&cprman BCM2835_CLOCK_H264>, -+ // <&cprman BCM2835_CLOCK_ISP>; -+ clock-names = "v3d", "peri_image", "h264", "isp"; -+ system-power-controller; -+ }; -+ -+ cprman: cprman@7d202000 { -+ compatible = "brcm,bcm2711-cprman"; -+ reg = <0x7d202000 0x2000>; -+ #clock-cells = <1>; -+ -+ /* CPRMAN derives almost everything from the -+ * platform's oscillator. However, the DSI -+ * pixel clocks come from the DSI analog PHY. -+ */ -+ clocks = <&clk_osc>; -+ status = "disabled"; -+ }; -+ -+ random: rng@7d208000 { -+ compatible = "brcm,bcm2711-rng200"; -+ reg = <0x7d208000 0x28>; -+ status = "okay"; -+ }; -+ -+ cpu_l2_irq: intc@7d503000 { -+ compatible = "brcm,l2-intc"; -+ reg = <0x7d503000 0x18>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ -+ pinctrl: pinctrl@7d504100 { -+ compatible = "brcm,bcm2712-pinctrl"; -+ reg = <0x7d504100 0x30>; -+ -+ uarta_24_pins: uarta_24_pins { -+ pin_rts { -+ function = "uart0"; -+ pins = "gpio24"; -+ bias-disable; -+ }; -+ pin_cts { -+ function = "uart0"; -+ pins = "gpio25"; -+ bias-pull-up; -+ }; -+ pin_txd { -+ function = "uart0"; -+ pins = "gpio26"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart0"; -+ pins = "gpio27"; -+ bias-pull-up; -+ }; -+ }; -+ -+ sdio2_30_pins: sdio2_30_pins { -+ pin_clk { -+ function = "sd2"; -+ pins = "gpio30"; -+ bias-disable; -+ }; -+ pin_cmd { -+ function = "sd2"; -+ pins = "gpio31"; -+ bias-pull-up; -+ }; -+ pins_dat { -+ function = "sd2"; -+ pins = "gpio32", "gpio33", "gpio34", "gpio35"; -+ bias-pull-up; -+ }; -+ }; -+ }; -+ -+ ddc0: i2c@7d508200 { -+ compatible = "brcm,brcmstb-i2c"; -+ reg = <0x7d508200 0x58>; -+ interrupt-parent = <&bsc_irq>; -+ interrupts = <1>; -+ clock-frequency = <97500>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ ddc1: i2c@7d508280 { -+ compatible = "brcm,brcmstb-i2c"; -+ reg = <0x7d508280 0x58>; -+ interrupt-parent = <&bsc_irq>; -+ interrupts = <2>; -+ clock-frequency = <97500>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ bscd: i2c@7d508300 { -+ compatible = "brcm,brcmstb-i2c"; -+ reg = <0x7d508300 0x58>; -+ interrupt-parent = <&bsc_irq>; -+ interrupts = <0>; -+ clock-frequency = <200000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ bsc_irq: intc@7d508380 { -+ compatible = "brcm,bcm7271-l2-intc"; -+ reg = <0x7d508380 0x10>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ -+ main_irq: intc@7d508400 { -+ compatible = "brcm,bcm7271-l2-intc"; -+ reg = <0x7d508400 0x10>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ -+ gio: gpio@7d508500 { -+ compatible = "brcm,brcmstb-gpio"; -+ reg = <0x7d508500 0x40>; -+ interrupt-parent = <&main_irq>; -+ interrupts = <0>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ brcm,gpio-bank-widths = <32 22>; -+ brcm,gpio-direct; -+ }; -+ -+ uarta: serial@7d50c000 { -+ compatible = "brcm,bcm7271-uart"; -+ reg = <0x7d50c000 0x20>; -+ reg-names = "uart"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ interrupts = ; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ uartb: serial@7d50d000 { -+ compatible = "brcm,bcm7271-uart"; -+ reg = <0x7d50d000 0x20>; -+ reg-names = "uart"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ interrupts = ; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ aon_intr: interrupt-controller@7d510600 { -+ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; -+ reg = <0x7d510600 0x30>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ status = "disabled"; -+ }; -+ -+ pinctrl_aon: pinctrl@7d510700 { -+ compatible = "brcm,bcm2712-aon-pinctrl"; -+ reg = <0x7d510700 0x20>; -+ -+ i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins { -+ function = "vc_i2c3"; -+ pins = "aon_gpio0", "aon_gpio1"; -+ bias-pull-up; -+ }; -+ -+ bsc_m1_agpio13_pins: bsc_m1_agpio13_pins { -+ function = "bsc_m1"; -+ pins = "aon_gpio13", "aon_gpio14"; -+ bias-pull-up; -+ }; -+ -+ bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins { -+ function = "avs_pmu_bsc"; -+ pins = "aon_sgpio4", "aon_sgpio5"; -+ }; -+ -+ bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins { -+ function = "bsc_m2"; -+ pins = "aon_sgpio4", "aon_sgpio5"; -+ }; -+ -+ pwm_aon_agpio1_pins: pwm_aon_agpio1_pins { -+ function = "aon_pwm"; -+ pins = "aon_gpio1", "aon_gpio2"; -+ }; -+ -+ pwm_aon_agpio4_pins: pwm_aon_agpio4_pins { -+ function = "vc_pwm0"; -+ pins = "aon_gpio4", "aon_gpio5"; -+ }; -+ -+ pwm_aon_agpio7_pins: pwm_aon_agpio7_pins { -+ function = "aon_pwm"; -+ pins = "aon_gpio7", "aon_gpio9"; -+ }; -+ }; -+ -+ intc@7d517000 { -+ compatible = "brcm,bcm7271-l2-intc"; -+ reg = <0x7d517000 0x10>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ status = "disabled"; -+ }; -+ -+ bscc: i2c@7d517a00 { -+ compatible = "brcm,brcmstb-i2c"; -+ reg = <0x7d517a00 0x58>; -+ interrupt-parent = <&bsc_aon_irq>; -+ interrupts = <0>; -+ clock-frequency = <200000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ pwm_aon: pwm@7d517a80 { -+ compatible = "brcm,bcm7038-pwm"; -+ reg = <0x7d517a80 0x28>; -+ #pwm-cells = <3>; -+ clocks = <&clk_27MHz>; -+ }; -+ -+ main_aon_irq: intc@7d517ac0 { -+ compatible = "brcm,bcm7271-l2-intc"; -+ reg = <0x7d517ac0 0x10>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ -+ bsc_aon_irq: intc@7d517b00 { -+ compatible = "brcm,bcm7271-l2-intc"; -+ reg = <0x7d517b00 0x10>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ -+ gio_aon: gpio@7d517c00 { -+ compatible = "brcm,brcmstb-gpio"; -+ reg = <0x7d517c00 0x40>; -+ interrupt-parent = <&main_aon_irq>; -+ interrupts = <0>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ brcm,gpio-bank-widths = <17 6>; -+ brcm,gpio-direct; -+ }; -+ -+ avs_monitor: avs-monitor@7d542000 { -+ compatible = "brcm,bcm2711-avs-monitor", -+ "syscon", "simple-mfd"; -+ reg = <0x7d542000 0xf00>; -+ status = "okay"; -+ -+ thermal: thermal { -+ compatible = "brcm,bcm2711-thermal"; -+ #thermal-sensor-cells = <0>; -+ }; -+ }; -+ -+ bsc_pmu: i2c@7d544000 { -+ compatible = "brcm,brcmstb-i2c"; -+ reg = <0x7d544000 0x58>; -+ interrupt-parent = <&bsc_aon_irq>; -+ interrupts = <1>; -+ clock-frequency = <200000>; -+ status = "disabled"; -+ }; -+ -+ hdmi0: hdmi@7ef00700 { -+ compatible = "brcm,bcm2712-hdmi0"; -+ reg = <0x7c701400 0x300>, -+ <0x7c701000 0x200>, -+ <0x7c701d00 0x300>, -+ <0x7c702000 0x80>, -+ <0x7c703800 0x200>, -+ <0x7c704000 0x800>, -+ <0x7c700100 0x80>, -+ <0x7d510800 0x100>, -+ <0x7c720000 0x100>; -+ reg-names = "hdmi", -+ "dvp", -+ "phy", -+ "rm", -+ "packet", -+ "metadata", -+ "csc", -+ "cec", -+ "hd"; -+ resets = <&dvp 1>; -+ interrupt-parent = <&aon_intr>; -+ interrupts = <1>, <2>, <3>, -+ <7>, <8>; -+ interrupt-names = "cec-tx", "cec-rx", "cec-low", -+ "hpd-connected", "hpd-removed"; -+ ddc = <&ddc0>; -+ dmas = <&dma32 10>; -+ dma-names = "audio-rx"; -+ status = "disabled"; -+ }; -+ -+ hdmi1: hdmi@7ef05700 { -+ compatible = "brcm,bcm2712-hdmi1"; -+ reg = <0x7c706400 0x300>, -+ <0x7c706000 0x200>, -+ <0x7c706d00 0x300>, -+ <0x7c707000 0x80>, -+ <0x7c708800 0x200>, -+ <0x7c709000 0x800>, -+ <0x7c700180 0x80>, -+ <0x7d511000 0x100>, -+ <0x7c720000 0x100>; -+ reg-names = "hdmi", -+ "dvp", -+ "phy", -+ "rm", -+ "packet", -+ "metadata", -+ "csc", -+ "cec", -+ "hd"; -+ ddc = <&ddc1>; -+ resets = <&dvp 2>; -+ interrupt-parent = <&aon_intr>; -+ interrupts = <11>, <12>, <13>, -+ <14>, <15>; -+ interrupt-names = "cec-tx", "cec-rx", "cec-low", -+ "hpd-connected", "hpd-removed"; -+ dmas = <&dma32 17>; -+ dma-names = "audio-rx"; -+ status = "disabled"; -+ }; -+ }; -+ -+ arm-pmu { -+ compatible = "arm,cortex-a76-pmu"; -+ interrupts = , -+ , -+ , -+ ; -+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; -+ }; -+ -+ timer { -+ compatible = "arm,armv8-timer"; -+ interrupts = , -+ , -+ , -+ ; -+ /* This only applies to the ARMv7 stub */ -+ arm,cpu-registers-not-fw-configured; -+ }; -+ -+ cpus: cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit -+ -+ /* Source for d/i cache-line-size, cache-sets, cache-size -+ * https://developer.arm.com/documentation/100798/0401 -+ * /L1-memory-system/About-the-L1-memory-system?lang=en -+ */ -+ cpu0: cpu@0 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a76"; -+ reg = <0x000>; -+ enable-method = "psci"; -+ d-cache-size = <0x10000>; -+ d-cache-line-size = <64>; -+ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ i-cache-size = <0x10000>; -+ i-cache-line-size = <64>; -+ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ next-level-cache = <&l2_cache_l0>; -+ }; -+ -+ cpu1: cpu@1 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a76"; -+ reg = <0x100>; -+ enable-method = "psci"; -+ d-cache-size = <0x10000>; -+ d-cache-line-size = <64>; -+ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ i-cache-size = <0x10000>; -+ i-cache-line-size = <64>; -+ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ next-level-cache = <&l2_cache_l1>; -+ }; -+ -+ cpu2: cpu@2 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a76"; -+ reg = <0x200>; -+ enable-method = "psci"; -+ d-cache-size = <0x10000>; -+ d-cache-line-size = <64>; -+ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ i-cache-size = <0x10000>; -+ i-cache-line-size = <64>; -+ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ next-level-cache = <&l2_cache_l2>; -+ }; -+ -+ cpu3: cpu@3 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a76"; -+ reg = <0x300>; -+ enable-method = "psci"; -+ d-cache-size = <0x10000>; -+ d-cache-line-size = <64>; -+ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ i-cache-size = <0x10000>; -+ i-cache-line-size = <64>; -+ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set -+ next-level-cache = <&l2_cache_l3>; -+ }; -+ -+ /* Source for cache-line-size and cache-sets: -+ * https://developer.arm.com/documentation/100798/0401 -+ * /L2-memory-system/About-the-L2-memory-system?lang=en -+ * and for cache-size: -+ * https://www.raspberrypi.com/documentation/computers -+ * /processors.html#bcm2712 -+ */ -+ l2_cache_l0: l2-cache-l0 { -+ compatible = "cache"; -+ cache-size = <0x80000>; -+ cache-line-size = <128>; -+ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set -+ cache-level = <2>; -+ cache-unified; -+ next-level-cache = <&l3_cache>; -+ }; -+ -+ l2_cache_l1: l2-cache-l1 { -+ compatible = "cache"; -+ cache-size = <0x80000>; -+ cache-line-size = <128>; -+ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set -+ cache-level = <2>; -+ cache-unified; -+ next-level-cache = <&l3_cache>; -+ }; -+ -+ l2_cache_l2: l2-cache-l2 { -+ compatible = "cache"; -+ cache-size = <0x80000>; -+ cache-line-size = <128>; -+ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set -+ cache-level = <2>; -+ cache-unified; -+ next-level-cache = <&l3_cache>; -+ }; -+ -+ l2_cache_l3: l2-cache-l3 { -+ compatible = "cache"; -+ cache-size = <0x80000>; -+ cache-line-size = <128>; -+ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set -+ cache-level = <2>; -+ cache-unified; -+ next-level-cache = <&l3_cache>; -+ }; -+ -+ /* Source for cache-line-size and cache-sets: -+ * https://developer.arm.com/documentation/100453/0401/L3-cache?lang=en -+ * Source for cache-size: -+ * https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712 -+ */ -+ l3_cache: l3-cache { -+ compatible = "cache"; -+ cache-size = <0x200000>; -+ cache-line-size = <64>; -+ cache-sets = <2048>; // 2MiB(size)/64(line-size)=32768ways/16-way set -+ cache-level = <3>; -+ }; -+ }; -+ -+ psci { -+ method = "smc"; -+ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; -+ cpu_on = <0xc4000003>; -+ cpu_suspend = <0xc4000001>; -+ cpu_off = <0x84000002>; -+ }; -+ -+ axi: axi { -+ compatible = "simple-bus"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ -+ ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, -+ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, -+ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, -+ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, -+ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; -+ -+ dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, -+ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, -+ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, -+ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, -+ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; -+ -+ vc4: gpu { -+ compatible = "brcm,bcm2712-vc6"; -+ }; -+ -+ iommu2: iommu@5100 { -+ /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */ -+ compatible = "brcm,bcm2712-iommu"; -+ reg = <0x10 0x5100 0x0 0x80>; -+ cache = <&iommuc>; -+ #iommu-cells = <0>; -+ }; -+ -+ iommu4: iommu@5200 { -+ /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */ -+ compatible = "brcm,bcm2712-iommu"; -+ reg = <0x10 0x5200 0x0 0x80>; -+ cache = <&iommuc>; -+ #iommu-cells = <0>; -+ #interconnect-cells = <0>; -+ }; -+ -+ iommu5: iommu@5280 { -+ /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */ -+ compatible = "brcm,bcm2712-iommu"; -+ reg = <0x10 0x5280 0x0 0x80>; -+ cache = <&iommuc>; -+ #iommu-cells = <0>; -+ dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe -+ }; -+ -+ iommuc: iommuc@5b00 { -+ compatible = "brcm,bcm2712-iommuc"; -+ reg = <0x10 0x5b00 0x0 0x80>; -+ }; -+ -+ dma32: dma@10000 { -+ compatible = "brcm,bcm2712-dma"; -+ reg = <0x10 0x00010000 0 0x600>; -+ interrupts = , -+ , -+ , -+ , -+ , -+ ; -+ interrupt-names = "dma0", -+ "dma1", -+ "dma2", -+ "dma3", -+ "dma4", -+ "dma5"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x0035>; -+ }; -+ -+ dma40: dma@10600 { -+ compatible = "brcm,bcm2712-dma"; -+ reg = <0x10 0x00010600 0 0x600>; -+ interrupts = -+ , /* dma4 6 */ -+ , /* dma4 7 */ -+ , /* dma4 8 */ -+ , /* dma4 9 */ -+ , /* dma4 10 */ -+ ; /* dma4 11 */ -+ interrupt-names = "dma6", -+ "dma7", -+ "dma8", -+ "dma9", -+ "dma10", -+ "dma11"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x0fc0>; -+ }; -+ -+ // Single-lane Gen3 PCIe -+ // Outbound window at 0x14_000000-0x17_ffffff -+ pcie0: pcie@100000 { -+ compatible = "brcm,bcm2712-pcie"; -+ reg = <0x10 0x00100000 0x0 0x9310>; -+ device_type = "pci"; -+ max-link-speed = <2>; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ /* -+ * Unused interrupts: -+ * 208: AER -+ * 215: NMI -+ * 216: PME -+ */ -+ interrupt-parent = <&gicv2>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 2 &gicv2 GIC_SPI 210 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 3 &gicv2 GIC_SPI 211 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 4 &gicv2 GIC_SPI 212 -+ IRQ_TYPE_LEVEL_HIGH>; -+ resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>; -+ reset-names = "swinit", "bridge", "rescal"; -+ msi-controller; -+ msi-parent = <&pcie0>; -+ -+ ranges = <0x02000000 0x00 0x00000000 -+ 0x17 0x00000000 -+ 0x0 0xfffffffc>, -+ <0x43000000 0x04 0x00000000 -+ 0x14 0x00000000 -+ 0x3 0x00000000>; -+ -+ dma-ranges = <0x43000000 0x10 0x00000000 -+ 0x00 0x00000000 -+ 0x10 0x00000000>; -+ -+ status = "disabled"; -+ }; -+ -+ // Single-lane Gen3 PCIe -+ // Outbound window at 0x18_000000-0x1b_ffffff -+ pcie1: pcie@110000 { -+ compatible = "brcm,bcm2712-pcie"; -+ reg = <0x10 0x00110000 0x0 0x9310>; -+ device_type = "pci"; -+ max-link-speed = <2>; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ /* -+ * Unused interrupts: -+ * 218: AER -+ * 225: NMI -+ * 226: PME -+ */ -+ interrupt-parent = <&gicv2>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 2 &gicv2 GIC_SPI 220 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 3 &gicv2 GIC_SPI 221 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 4 &gicv2 GIC_SPI 222 -+ IRQ_TYPE_LEVEL_HIGH>; -+ resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>; -+ reset-names = "swinit", "bridge", "rescal"; -+ msi-controller; -+ msi-parent = <&mip1>; -+ -+ ranges = <0x02000000 0x00 0x00000000 -+ 0x1b 0x00000000 -+ 0x00 0xfffffffc>, -+ <0x43000000 0x04 0x00000000 -+ 0x18 0x00000000 -+ 0x03 0x00000000>; -+ -+ dma-ranges = <0x03000000 0x10 0x00000000 -+ 0x00 0x00000000 -+ 0x10 0x00000000>; -+ -+ brcm,enable-l1ss; -+ status = "disabled"; -+ }; -+ -+ pcie_rescal: reset-controller@119500 { -+ compatible = "brcm,bcm7216-pcie-sata-rescal"; -+ reg = <0x10 0x00119500 0x0 0x10>; -+ #reset-cells = <0>; -+ }; -+ -+ // Quad-lane Gen3 PCIe -+ // Outbound window at 0x1c_000000-0x1f_ffffff -+ pcie2: pcie@120000 { -+ compatible = "brcm,bcm2712-pcie"; -+ reg = <0x10 0x00120000 0x0 0x9310>; -+ device_type = "pci"; -+ max-link-speed = <2>; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ /* -+ * Unused interrupts: -+ * 228: AER -+ * 235: NMI -+ * 236: PME -+ */ -+ interrupt-parent = <&gicv2>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 2 &gicv2 GIC_SPI 230 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 3 &gicv2 GIC_SPI 231 -+ IRQ_TYPE_LEVEL_HIGH>, -+ <0 0 0 4 &gicv2 GIC_SPI 232 -+ IRQ_TYPE_LEVEL_HIGH>; -+ resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>; -+ reset-names = "swinit", "bridge", "rescal"; -+ msi-controller; -+ msi-parent = <&mip0>; -+ -+ // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000 -+ ranges = <0x02000000 0x00 0x00000000 -+ 0x1f 0x00000000 -+ 0x0 0xfffffffc>, -+ // 12GB, 64-bit, prefetchable at PCIe 04_00000000 -+ <0x43000000 0x04 0x00000000 -+ 0x1c 0x00000000 -+ 0x03 0x00000000>; -+ -+ // 64GB system RAM space at PCIe 10_00000000 -+ dma-ranges = <0x02000000 0x00 0x00000000 -+ 0x1f 0x00000000 -+ 0x00 0x00400000>, -+ <0x43000000 0x10 0x00000000 -+ 0x00 0x00000000 -+ 0x10 0x00000000>; -+ -+ brcm,enable-l1ss; -+ status = "disabled"; -+ }; -+ -+ mip0: msi-controller@130000 { -+ compatible = "brcm,bcm2712-mip-intc"; -+ reg = <0x10 0x00130000 0x0 0xc0>; -+ msi-controller; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ brcm,msi-base-spi = <128>; -+ brcm,msi-num-spis = <64>; -+ brcm,msi-offset = <0>; -+ brcm,msi-pci-addr = <0xff 0xfffff000>; -+ }; -+ -+ mip1: msi-controller@131000 { -+ compatible = "brcm,bcm2712-mip-intc"; -+ reg = <0x10 0x00131000 0x0 0xc0>; -+ msi-controller; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ brcm,msi-base-spi = <247>; -+ /* Actually 20 total, but the others are -+ * both sparse and non-consecutive */ -+ brcm,msi-num-spis = <8>; -+ brcm,msi-offset = <8>; -+ brcm,msi-pci-addr = <0xff 0xffffe000>; -+ }; -+ -+ syscon_piarbctl: syscon@400018 { -+ compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd"; -+ reg = <0x10 0x00400018 0x0 0x18>; -+ }; -+ -+ usb: usb@480000 { -+ compatible = "brcm,bcm2835-usb"; -+ reg = <0x10 0x00480000 0x0 0x10000>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clk_usb>; -+ clock-names = "otg"; -+ phys = <&usbphy>; -+ phy-names = "usb2-phy"; -+ status = "disabled"; -+ }; -+ -+ rpivid: codec@800000 { -+ compatible = "raspberrypi,rpivid-vid-decoder"; -+ reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ -+ <0x10 0x00840000 0x0 0x1000>; /* INTC */ -+ reg-names = "hevc", -+ "intc"; -+ -+ interrupts = ; -+ -+ clocks = <&firmware_clocks 11>; -+ clock-names = "hevc"; -+ iommus = <&iommu2>; -+ status = "disabled"; -+ }; -+ -+ sdio1: mmc@fff000 { -+ compatible = "brcm,bcm2712-sdhci"; -+ reg = <0x10 0x00fff000 0x0 0x260>, -+ <0x10 0x00fff400 0x0 0x200>, -+ <0x10 0x015040b0 0x0 0x4>, // Bus isolation control -+ <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8 -+ reg-names = "host", "cfg", "busisol", "lcpll"; -+ interrupts = ; -+ clocks = <&clk_emmc2>; -+ sdhci-caps-mask = <0x0000C000 0x0>; -+ sdhci-caps = <0x0 0x0>; -+ mmc-ddr-3_3v; -+ }; -+ -+ sdio2: mmc@1100000 { -+ compatible = "brcm,bcm2712-sdhci"; -+ reg = <0x10 0x01100000 0x0 0x260>, -+ <0x10 0x01100400 0x0 0x200>; -+ reg-names = "host", "cfg"; -+ interrupts = ; -+ clocks = <&clk_emmc2>; -+ sdhci-caps-mask = <0x0000C000 0x0>; -+ sdhci-caps = <0x0 0x0>; -+ supports-cqe; -+ mmc-ddr-3_3v; -+ status = "disabled"; -+ }; -+ -+ bcm_reset: reset-controller@1504318 { -+ compatible = "brcm,brcmstb-reset"; -+ reg = <0x10 0x01504318 0x0 0x30>; -+ #reset-cells = <1>; -+ }; -+ -+ v3d: v3d@2000000 { -+ compatible = "brcm,2712-v3d"; -+ reg = <0x10 0x02000000 0x0 0x4000>, -+ <0x10 0x02008000 0x0 0x6000>; -+ reg-names = "hub", "core0"; -+ -+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; -+ resets = <&pm BCM2835_RESET_V3D>; -+ clocks = <&firmware_clocks 5>; -+ clocks-names = "v3d"; -+ interrupts = , -+ ; -+ status = "disabled"; -+ }; -+ -+ gicv2: interrupt-controller@7fff9000 { -+ interrupt-controller; -+ #interrupt-cells = <3>; -+ compatible = "arm,gic-400"; -+ reg = <0x10 0x7fff9000 0x0 0x1000>, -+ <0x10 0x7fffa000 0x0 0x2000>, -+ <0x10 0x7fffc000 0x0 0x2000>, -+ <0x10 0x7fffe000 0x0 0x2000>; -+ interrupts = ; -+ }; -+ -+ pisp_be: pisp_be@880000 { -+ compatible = "raspberrypi,pispbe"; -+ reg = <0x10 0x00880000 0x0 0x4000>; -+ interrupts = ; -+ clocks = <&firmware_clocks 7>; -+ clocks-names = "isp_be"; -+ status = "okay"; -+ iommus = <&iommu2>; -+ }; -+ }; -+ -+ clocks { -+ /* The oscillator is the root of the clock tree. */ -+ clk_osc: clk-osc { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "osc"; -+ clock-frequency = <54000000>; -+ }; -+ -+ clk_usb: clk-usb { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "otg"; -+ clock-frequency = <480000000>; -+ }; -+ -+ clk_vpu: clk_vpu { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <750000000>; -+ clock-output-names = "vpu-clock"; -+ }; -+ -+ clk_uart: clk_uart { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <9216000>; -+ clock-output-names = "uart-clock"; -+ }; -+ -+ clk_emmc2: clk_emmc2 { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <200000000>; -+ clock-output-names = "emmc2-clock"; -+ }; -+ }; -+ -+ usbphy: phy { -+ compatible = "usb-nop-xceiv"; -+ #phy-cells = <0>; -+ }; -+}; -diff --git a/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts b/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts -new file mode 100644 -index 000000000000..32aab40524b3 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts -@@ -0,0 +1,107 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include "bcm2712-rpi-5-b.dts" -+ -+&gio { -+ brcm,gpio-bank-widths = <32 4>; -+ -+ gpio-line-names = -+ "", // GPIO_000 -+ "2712_BOOT_CS_N", // GPIO_001 -+ "2712_BOOT_MISO", // GPIO_002 -+ "2712_BOOT_MOSI", // GPIO_003 -+ "2712_BOOT_SCLK", // GPIO_004 -+ "", // GPIO_005 -+ "", // GPIO_006 -+ "", // GPIO_007 -+ "", // GPIO_008 -+ "", // GPIO_009 -+ "", // GPIO_010 -+ "", // GPIO_011 -+ "", // GPIO_012 -+ "", // GPIO_013 -+ "PCIE_SDA", // GPIO_014 -+ "PCIE_SCL", // GPIO_015 -+ "", // GPIO_016 -+ "", // GPIO_017 -+ "-", // GPIO_018 -+ "-", // GPIO_019 -+ "PWR_GPIO", // GPIO_020 -+ "2712_G21_FS", // GPIO_021 -+ "-", // GPIO_022 -+ "-", // GPIO_023 -+ "BT_RTS", // GPIO_024 -+ "BT_CTS", // GPIO_025 -+ "BT_TXD", // GPIO_026 -+ "BT_RXD", // GPIO_027 -+ "WL_ON", // GPIO_028 -+ "BT_ON", // GPIO_029 -+ "WIFI_SDIO_CLK", // GPIO_030 -+ "WIFI_SDIO_CMD", // GPIO_031 -+ "WIFI_SDIO_D0", // GPIO_032 -+ "WIFI_SDIO_D1", // GPIO_033 -+ "WIFI_SDIO_D2", // GPIO_034 -+ "WIFI_SDIO_D3"; // GPIO_035 -+}; -+ -+&gio_aon { -+ brcm,gpio-bank-widths = <15 6>; -+ -+ gpio-line-names = -+ "RP1_SDA", // AON_GPIO_00 -+ "RP1_SCL", // AON_GPIO_01 -+ "RP1_RUN", // AON_GPIO_02 -+ "SD_IOVDD_SEL", // AON_GPIO_03 -+ "SD_PWR_ON", // AON_GPIO_04 -+ "SD_CDET_N", // AON_GPIO_05 -+ "SD_FLG_N", // AON_GPIO_06 -+ "", // AON_GPIO_07 -+ "2712_WAKE", // AON_GPIO_08 -+ "2712_STAT_LED", // AON_GPIO_09 -+ "", // AON_GPIO_10 -+ "", // AON_GPIO_11 -+ "PMIC_INT", // AON_GPIO_12 -+ "UART_TX_FS", // AON_GPIO_13 -+ "UART_RX_FS", // AON_GPIO_14 -+ "", // AON_GPIO_15 -+ "", // AON_GPIO_16 -+ -+ // Pad bank0 out to 32 entries -+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", -+ -+ "HDMI0_SCL", // AON_SGPIO_00 -+ "HDMI0_SDA", // AON_SGPIO_01 -+ "HDMI1_SCL", // AON_SGPIO_02 -+ "HDMI1_SDA", // AON_SGPIO_03 -+ "PMIC_SCL", // AON_SGPIO_04 -+ "PMIC_SDA"; // AON_SGPIO_05 -+}; -+ -+&pinctrl { -+ compatible = "brcm,bcm2712d0-pinctrl"; -+ reg = <0x7d504100 0x20>; -+}; -+ -+&pinctrl_aon { -+ compatible = "brcm,bcm2712d0-aon-pinctrl"; -+ reg = <0x7d510700 0x1c>; -+}; -+ -+&vc4 { -+ compatible = "brcm,bcm2712d0-vc6"; -+}; -+ -+&uart10 { -+ interrupts = ; -+}; -+ -+&spi10 { -+ dmas = <&dma40 3>, <&dma40 4>; -+}; -+ -+&hdmi0 { -+ dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; -+}; -+ -+&hdmi1 { -+ dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; -+}; diff --git a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi new file mode 100644 -index 000000000000..400efdc5f03c +index 000000000000..c77e280ccd16 --- /dev/null +++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi -@@ -0,0 +1,38 @@ +@@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 + +&uart0 { @@ -14607,6 +11871,10 @@ index 000000000000..400efdc5f03c +}; + +/ { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory"; ++ }; ++ + aliases { + bluetooth = &bt; + }; @@ -14671,7 +11939,7 @@ index 000000000000..119946d878db + pinctrl-1 = <&i2c0_gpio44>; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm283x.dtsi b/arch/arm/boot/dts/broadcom/bcm283x.dtsi -index 2ca8a2505a4d..c7a645647323 100644 +index 2ca8a2505a4d..6f09d96e1192 100644 --- a/arch/arm/boot/dts/broadcom/bcm283x.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm283x.dtsi @@ -363,7 +363,7 @@ dsi0: dsi@7e209000 { @@ -14692,1325 +11960,23 @@ index 2ca8a2505a4d..c7a645647323 100644 #pwm-cells = <3>; status = "disabled"; }; -diff --git a/arch/arm/boot/dts/broadcom/rp1.dtsi b/arch/arm/boot/dts/broadcom/rp1.dtsi -new file mode 100644 -index 000000000000..fd9fb2dde0f7 ---- /dev/null -+++ b/arch/arm/boot/dts/broadcom/rp1.dtsi -@@ -0,0 +1,1307 @@ -+#include -+#include -+#include -+ -+&rp1_target { -+ rp1: rp1 { +@@ -478,6 +478,10 @@ usb: usb@7e980000 { + }; + + clocks { + compatible = "simple-bus"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ #interrupt-cells = <2>; -+ interrupt-controller; -+ interrupt-parent = <&rp1>; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ // ranges and dma-ranges must be provided by the includer -+ -+ rp1_clocks: clocks@18000 { -+ compatible = "raspberrypi,rp1-clocks"; -+ #clock-cells = <1>; -+ reg = <0xc0 0x40018000 0x0 0x10038>; -+ clocks = <&clk_xosc>; -+ -+ assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>, -+ <&rp1_clocks RP1_PLL_AUDIO_CORE>, -+ // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers -+ <&rp1_clocks RP1_PLL_SYS>, -+ <&rp1_clocks RP1_PLL_SYS_SEC>, -+ <&rp1_clocks RP1_PLL_AUDIO>, -+ <&rp1_clocks RP1_PLL_AUDIO_SEC>, -+ <&rp1_clocks RP1_CLK_SYS>, -+ <&rp1_clocks RP1_PLL_SYS_PRI_PH>, -+ // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0) -+ <&rp1_clocks RP1_CLK_SLOW_SYS>, -+ <&rp1_clocks RP1_CLK_SDIO_TIMER>, -+ <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>, -+ <&rp1_clocks RP1_CLK_ETH_TSU>; -+ -+ assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE -+ <1536000000>, // RP1_PLL_AUDIO_CORE -+ <200000000>, // RP1_PLL_SYS -+ <125000000>, // RP1_PLL_SYS_SEC -+ <61440000>, // RP1_PLL_AUDIO -+ <192000000>, // RP1_PLL_AUDIO_SEC -+ <200000000>, // RP1_CLK_SYS -+ <100000000>, // RP1_PLL_SYS_PRI_PH -+ // Must match the XOSC frequency -+ <50000000>, // RP1_CLK_SLOW_SYS -+ <1000000>, // RP1_CLK_SDIO_TIMER -+ <200000000>, // RP1_CLK_SDIO_ALT_SRC -+ <50000000>; // RP1_CLK_ETH_TSU -+ }; -+ -+ rp1_uart0: serial@30000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x40030000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ dmas = <&rp1_dma RP1_DMA_UART0_TX>, -+ <&rp1_dma RP1_DMA_UART0_RX>; -+ dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_uart1: serial@34000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x40034000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ // dmas = <&rp1_dma RP1_DMA_UART1_TX>, -+ // <&rp1_dma RP1_DMA_UART1_RX>; -+ // dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_uart2: serial@38000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x40038000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ // dmas = <&rp1_dma RP1_DMA_UART2_TX>, -+ // <&rp1_dma RP1_DMA_UART2_RX>; -+ // dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_uart3: serial@3c000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x4003c000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ // dmas = <&rp1_dma RP1_DMA_UART3_TX>, -+ // <&rp1_dma RP1_DMA_UART3_RX>; -+ // dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_uart4: serial@40000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x40040000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ // dmas = <&rp1_dma RP1_DMA_UART4_TX>, -+ // <&rp1_dma RP1_DMA_UART4_RX>; -+ // dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_uart5: serial@44000 { -+ compatible = "arm,pl011-axi"; -+ reg = <0xc0 0x40044000 0x0 0x100>; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; -+ clock-names = "uartclk", "apb_pclk"; -+ // dmas = <&rp1_dma RP1_DMA_UART5_TX>, -+ // <&rp1_dma RP1_DMA_UART5_RX>; -+ // dma-names = "tx", "rx"; -+ pinctrl-names = "default"; -+ arm,primecell-periphid = <0x00541011>; -+ uart-has-rtscts; -+ cts-event-workaround; -+ skip-init; -+ status = "disabled"; -+ }; -+ -+ rp1_spi8: spi@4c000 { -+ reg = <0xc0 0x4004c000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI8_TX>, -+ <&rp1_dma RP1_DMA_SPI8_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_spi0: spi@50000 { -+ reg = <0xc0 0x40050000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI0_TX>, -+ <&rp1_dma RP1_DMA_SPI0_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_spi1: spi@54000 { -+ reg = <0xc0 0x40054000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI1_TX>, -+ <&rp1_dma RP1_DMA_SPI1_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_spi2: spi@58000 { -+ reg = <0xc0 0x40058000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI2_TX>, -+ <&rp1_dma RP1_DMA_SPI2_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_spi3: spi@5c000 { -+ reg = <0xc0 0x4005c000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI3_TX>, -+ <&rp1_dma RP1_DMA_SPI3_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ // SPI4 is a target/slave interface -+ rp1_spi4: spi@60000 { -+ reg = <0xc0 0x40060000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <0>; -+ #size-cells = <0>; -+ num-cs = <1>; -+ spi-slave; -+ dmas = <&rp1_dma RP1_DMA_SPI4_TX>, -+ <&rp1_dma RP1_DMA_SPI4_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ -+ slave { -+ compatible = "spidev"; -+ spi-max-frequency = <1000000>; -+ }; -+ }; -+ -+ rp1_spi5: spi@64000 { -+ reg = <0xc0 0x40064000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI5_TX>, -+ <&rp1_dma RP1_DMA_SPI5_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_spi6: spi@68000 { -+ reg = <0xc0 0x40068000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ num-cs = <2>; -+ dmas = <&rp1_dma RP1_DMA_SPI6_TX>, -+ <&rp1_dma RP1_DMA_SPI6_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ // SPI7 is a target/slave interface -+ rp1_spi7: spi@6c000 { -+ reg = <0xc0 0x4006c000 0x0 0x130>; -+ compatible = "snps,dw-apb-ssi"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ clock-names = "ssi_clk"; -+ #address-cells = <0>; -+ #size-cells = <0>; -+ num-cs = <1>; -+ spi-slave; -+ dmas = <&rp1_dma RP1_DMA_SPI7_TX>, -+ <&rp1_dma RP1_DMA_SPI7_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ -+ slave { -+ compatible = "spidev"; -+ spi-max-frequency = <1000000>; -+ }; -+ }; -+ -+ rp1_i2c0: i2c@70000 { -+ reg = <0xc0 0x40070000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c1: i2c@74000 { -+ reg = <0xc0 0x40074000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c2: i2c@78000 { -+ reg = <0xc0 0x40078000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c3: i2c@7c000 { -+ reg = <0xc0 0x4007c000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c4: i2c@80000 { -+ reg = <0xc0 0x40080000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c5: i2c@84000 { -+ reg = <0xc0 0x40084000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2c6: i2c@88000 { -+ reg = <0xc0 0x40088000 0x0 0x1000>; -+ compatible = "snps,designware-i2c"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS>; -+ i2c-scl-rising-time-ns = <65>; -+ i2c-scl-falling-time-ns = <100>; -+ status = "disabled"; -+ }; -+ -+ rp1_pwm0: pwm@98000 { -+ compatible = "raspberrypi,rp1-pwm"; -+ reg = <0xc0 0x40098000 0x0 0x100>; -+ #pwm-cells = <3>; -+ clocks = <&rp1_clocks RP1_CLK_PWM0>; -+ assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>; -+ assigned-clock-rates = <50000000>; -+ status = "disabled"; -+ }; -+ -+ rp1_pwm1: pwm@9c000 { -+ compatible = "raspberrypi,rp1-pwm"; -+ reg = <0xc0 0x4009c000 0x0 0x100>; -+ #pwm-cells = <3>; -+ clocks = <&rp1_clocks RP1_CLK_PWM1>; -+ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>; -+ assigned-clock-rates = <50000000>; -+ status = "disabled"; -+ }; -+ -+ rp1_i2s0: i2s@a0000 { -+ reg = <0xc0 0x400a0000 0x0 0x1000>; -+ compatible = "snps,designware-i2s"; -+ // Providing an interrupt disables DMA -+ // interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_I2S>; -+ clock-names = "i2sclk"; -+ #sound-dai-cells = <0>; -+ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_i2s1: i2s@a4000 { -+ reg = <0xc0 0x400a4000 0x0 0x1000>; -+ compatible = "snps,designware-i2s"; -+ // Providing an interrupt disables DMA -+ // interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_I2S>; -+ clock-names = "i2sclk"; -+ #sound-dai-cells = <0>; -+ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>; -+ dma-names = "tx", "rx"; -+ status = "disabled"; -+ }; -+ -+ rp1_i2s2: i2s@a8000 { -+ reg = <0xc0 0x400a8000 0x0 0x1000>; -+ compatible = "snps,designware-i2s"; -+ // Providing an interrupt disables DMA -+ // interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_I2S>; -+ status = "disabled"; -+ }; -+ -+ rp1_sdio_clk0: sdio_clk0@b0004 { -+ compatible = "raspberrypi,rp1-sdio-clk"; -+ reg = <0xc0 0x400b0004 0x0 0x1c>; -+ clocks = <&sdio_src &sdhci_core>; -+ clock-names = "src", "base"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ rp1_sdio_clk1: sdio_clk1@b4004 { -+ compatible = "raspberrypi,rp1-sdio-clk"; -+ reg = <0xc0 0x400b4004 0x0 0x1c>; -+ clocks = <&sdio_src &sdhci_core>; -+ clock-names = "src", "base"; -+ #clock-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ rp1_adc: adc@c8000 { -+ compatible = "raspberrypi,rp1-adc"; -+ reg = <0xc0 0x400c8000 0x0 0x4000>; -+ clocks = <&rp1_clocks RP1_CLK_ADC>; -+ clock-names = "adcclk"; -+ #clock-cells = <0>; -+ vref-supply = <&rp1_vdd_3v3>; -+ status = "disabled"; -+ }; -+ -+ rp1_gpio: gpio@d0000 { -+ reg = <0xc0 0x400d0000 0x0 0xc000>, -+ <0xc0 0x400e0000 0x0 0xc000>, -+ <0xc0 0x400f0000 0x0 0xc000>; -+ compatible = "raspberrypi,rp1-gpio"; -+ interrupts = , -+ , -+ ; -+ gpio-controller; -+ #gpio-cells = <2>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ gpio-ranges = <&rp1_gpio 0 0 54>; -+ -+ rp1_uart0_14_15: rp1_uart0_14_15 { -+ pin_txd { -+ function = "uart0"; -+ pins = "gpio14"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart0"; -+ pins = "gpio15"; -+ bias-pull-up; -+ }; -+ }; -+ rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 { -+ pin_cts { -+ function = "uart0"; -+ pins = "gpio16"; -+ bias-pull-up; -+ }; -+ pin_rts { -+ function = "uart0"; -+ pins = "gpio17"; -+ bias-disable; -+ }; -+ }; -+ rp1_uart1_0_1: rp1_uart1_0_1 { -+ pin_txd { -+ function = "uart1"; -+ pins = "gpio0"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart1"; -+ pins = "gpio1"; -+ bias-pull-up; -+ }; -+ }; -+ rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 { -+ pin_cts { -+ function = "uart1"; -+ pins = "gpio2"; -+ bias-pull-up; -+ }; -+ pin_rts { -+ function = "uart1"; -+ pins = "gpio3"; -+ bias-disable; -+ }; -+ }; -+ rp1_uart2_4_5: rp1_uart2_4_5 { -+ pin_txd { -+ function = "uart2"; -+ pins = "gpio4"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart2"; -+ pins = "gpio5"; -+ bias-pull-up; -+ }; -+ }; -+ rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 { -+ pin_cts { -+ function = "uart2"; -+ pins = "gpio6"; -+ bias-pull-up; -+ }; -+ pin_rts { -+ function = "uart2"; -+ pins = "gpio7"; -+ bias-disable; -+ }; -+ }; -+ rp1_uart3_8_9: rp1_uart3_8_9 { -+ pin_txd { -+ function = "uart3"; -+ pins = "gpio8"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart3"; -+ pins = "gpio9"; -+ bias-pull-up; -+ }; -+ }; -+ rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 { -+ pin_cts { -+ function = "uart3"; -+ pins = "gpio10"; -+ bias-pull-up; -+ }; -+ pin_rts { -+ function = "uart3"; -+ pins = "gpio11"; -+ bias-disable; -+ }; -+ }; -+ rp1_uart4_12_13: rp1_uart4_12_13 { -+ pin_txd { -+ function = "uart4"; -+ pins = "gpio12"; -+ bias-disable; -+ }; -+ pin_rxd { -+ function = "uart4"; -+ pins = "gpio13"; -+ bias-pull-up; -+ }; -+ }; -+ rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 { -+ pin_cts { -+ function = "uart4"; -+ pins = "gpio14"; -+ bias-pull-up; -+ }; -+ pin_rts { -+ function = "uart4"; -+ pins = "gpio15"; -+ bias-disable; -+ }; -+ }; -+ -+ rp1_sdio0_22_27: rp1_sdio0_22_27 { -+ pin_clk { -+ function = "sd0"; -+ pins = "gpio22"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ pin_cmd { -+ function = "sd0"; -+ pins = "gpio23"; -+ bias-pull-up; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ pins_dat { -+ function = "sd0"; -+ pins = "gpio24", "gpio25", "gpio26", "gpio27"; -+ bias-pull-up; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ }; -+ -+ rp1_sdio1_28_33: rp1_sdio1_28_33 { -+ pin_clk { -+ function = "sd1"; -+ pins = "gpio28"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ pin_cmd { -+ function = "sd1"; -+ pins = "gpio29"; -+ bias-pull-up; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ pins_dat { -+ function = "sd1"; -+ pins = "gpio30", "gpio31", "gpio32", "gpio33"; -+ bias-pull-up; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ }; -+ -+ rp1_i2s0_18_21: rp1_i2s0_18_21 { -+ function = "i2s0"; -+ pins = "gpio18", "gpio19", "gpio20", "gpio21"; -+ bias-disable; -+ }; -+ -+ rp1_i2s1_18_21: rp1_i2s1_18_21 { -+ function = "i2s1"; -+ pins = "gpio18", "gpio19", "gpio20", "gpio21"; -+ bias-disable; -+ }; -+ -+ rp1_i2c4_34_35: rp1_i2c4_34_35 { -+ function = "i2c4"; -+ pins = "gpio34", "gpio35"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c6_38_39: rp1_i2c6_38_39 { -+ function = "i2c6"; -+ pins = "gpio38", "gpio39"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c4_40_41: rp1_i2c4_40_41 { -+ function = "i2c4"; -+ pins = "gpio40", "gpio41"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c5_44_45: rp1_i2c5_44_45 { -+ function = "i2c5"; -+ pins = "gpio44", "gpio45"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c0_0_1: rp1_i2c0_0_1 { -+ function = "i2c0"; -+ pins = "gpio0", "gpio1"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c0_8_9: rp1_i2c0_8_9 { -+ function = "i2c0"; -+ pins = "gpio8", "gpio9"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c1_2_3: rp1_i2c1_2_3 { -+ function = "i2c1"; -+ pins = "gpio2", "gpio3"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c1_10_11: rp1_i2c1_10_11 { -+ function = "i2c1"; -+ pins = "gpio10", "gpio11"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c2_4_5: rp1_i2c2_4_5 { -+ function = "i2c2"; -+ pins = "gpio4", "gpio5"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c2_12_13: rp1_i2c2_12_13 { -+ function = "i2c2"; -+ pins = "gpio12", "gpio13"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c3_6_7: rp1_i2c3_6_7 { -+ function = "i2c3"; -+ pins = "gpio6", "gpio7"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c3_14_15: rp1_i2c3_14_15 { -+ function = "i2c3"; -+ pins = "gpio14", "gpio15"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ rp1_i2c3_22_23: rp1_i2c3_22_23 { -+ function = "i2c3"; -+ pins = "gpio22", "gpio23"; -+ drive-strength = <12>; -+ bias-pull-up; -+ }; -+ -+ // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE -+ rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", "gpio4", "gpio5", -+ "gpio6", "gpio7", "gpio8", "gpio9", -+ "gpio10", "gpio11", "gpio12", "gpio13", -+ "gpio14", "gpio15", "gpio16", "gpio17", -+ "gpio18", "gpio19"; -+ bias-disable; -+ }; -+ rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", "gpio4", "gpio5", -+ "gpio6", "gpio7", "gpio8", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio20", "gpio21", "gpio22", "gpio23", -+ "gpio24"; -+ bias-disable; -+ }; -+ rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", -+ "gpio5", "gpio6", "gpio7", "gpio8", -+ "gpio9", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio21", "gpio22", "gpio23", "gpio24", -+ "gpio25"; -+ bias-disable; -+ }; -+ rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", "gpio4", "gpio5", -+ "gpio6", "gpio7", "gpio8", "gpio9", -+ "gpio10", "gpio11", "gpio12", "gpio13", -+ "gpio14", "gpio15", "gpio16", "gpio17", -+ "gpio18", "gpio19", "gpio20", "gpio21"; -+ bias-disable; -+ }; -+ rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", "gpio4", "gpio5", -+ "gpio6", "gpio7", "gpio8", "gpio9", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio20", "gpio21", "gpio22", "gpio23", -+ "gpio24", "gpio25"; -+ bias-disable; -+ }; -+ rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3", "gpio4", "gpio5", -+ "gpio6", "gpio7", "gpio8", "gpio9", -+ "gpio10", "gpio11", "gpio12", "gpio13", -+ "gpio14", "gpio15", "gpio16", "gpio17", -+ "gpio18", "gpio19", "gpio20", "gpio21", -+ "gpio22", "gpio23", "gpio24", "gpio25", -+ "gpio26", "gpio27"; -+ bias-disable; -+ }; -+ rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */ -+ function = "dpi"; -+ pins = "gpio2", "gpio3"; -+ bias-disable; -+ }; -+ -+ // More DPI mappings, including PIXCLK,DE on GPIOs 0,1 -+ rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio4", "gpio5", "gpio6", "gpio7", -+ "gpio8", "gpio9", "gpio10", "gpio11", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", "gpio18", "gpio19"; -+ bias-disable; -+ }; -+ rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio4", "gpio5", "gpio6", "gpio7", -+ "gpio8", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio20", "gpio21", "gpio22", "gpio23", -+ "gpio24"; -+ bias-disable; -+ }; -+ rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio5", "gpio6", "gpio7", "gpio8", -+ "gpio9", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio21", "gpio22", "gpio23", "gpio24", -+ "gpio25"; -+ bias-disable; -+ }; -+ rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio4", "gpio5", "gpio6", "gpio7", -+ "gpio8", "gpio9", "gpio10", "gpio11", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", "gpio18", "gpio19", -+ "gpio20", "gpio21"; -+ bias-disable; -+ }; -+ rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio4", "gpio5", "gpio6", "gpio7", -+ "gpio8", "gpio9", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", -+ "gpio20", "gpio21", "gpio22", "gpio23", -+ "gpio24", "gpio25"; -+ bias-disable; -+ }; -+ rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */ -+ function = "dpi"; -+ pins = "gpio0", "gpio1", "gpio2", "gpio3", -+ "gpio4", "gpio5", "gpio6", "gpio7", -+ "gpio8", "gpio9", "gpio10", "gpio11", -+ "gpio12", "gpio13", "gpio14", "gpio15", -+ "gpio16", "gpio17", "gpio18", "gpio19", -+ "gpio20", "gpio21", "gpio22", "gpio23", -+ "gpio24", "gpio25", "gpio26", "gpio27"; -+ bias-disable; -+ }; -+ -+ rp1_gpclksrc0_gpio4: rp1_gpclksrc0_gpio4 { -+ function = "gpclk0"; -+ pins = "gpio4"; -+ bias-disable; -+ }; -+ -+ rp1_gpclksrc0_gpio20: rp1_gpclksrc0_gpio20 { -+ function = "gpclk0"; -+ pins = "gpio20"; -+ bias-disable; -+ }; -+ -+ rp1_gpclksrc1_gpio5: rp1_gpclksrc1_gpio5 { -+ function = "gpclk1"; -+ pins = "gpio5"; -+ bias-disable; -+ }; -+ -+ rp1_gpclksrc1_gpio18: rp1_gpclksrc1_gpio18 { -+ function = "gpclk1"; -+ pins = "gpio18"; -+ bias-disable; -+ }; -+ -+ rp1_gpclksrc1_gpio21: rp1_gpclksrc1_gpio21 { -+ function = "gpclk1"; -+ pins = "gpio21"; -+ bias-disable; -+ }; -+ -+ rp1_pwm1_gpio45: rp1_pwm1_gpio45 { -+ function = "pwm1"; -+ pins = "gpio45"; -+ bias-pull-down; -+ }; -+ -+ rp1_spi0_gpio9: rp1_spi0_gpio9 { -+ function = "spi0"; -+ pins = "gpio9", "gpio10", "gpio11"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 { -+ function = "spi0"; -+ pins = "gpio7", "gpio8"; -+ bias-pull-up; -+ }; -+ -+ rp1_spi1_gpio19: rp1_spi1_gpio19 { -+ function = "spi1"; -+ pins = "gpio19", "gpio20", "gpio21"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi2_gpio1: rp1_spi2_gpio1 { -+ function = "spi2"; -+ pins = "gpio1", "gpio2", "gpio3"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi3_gpio5: rp1_spi3_gpio5 { -+ function = "spi3"; -+ pins = "gpio5", "gpio6", "gpio7"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi4_gpio9: rp1_spi4_gpio9 { -+ function = "spi4"; -+ pins = "gpio9", "gpio10", "gpio11"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi5_gpio13: rp1_spi5_gpio13 { -+ function = "spi5"; -+ pins = "gpio13", "gpio14", "gpio15"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi8_gpio49: rp1_spi8_gpio49 { -+ function = "spi8"; -+ pins = "gpio49", "gpio50", "gpio51"; -+ bias-disable; -+ drive-strength = <12>; -+ slew-rate = <1>; -+ }; -+ -+ rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 { -+ function = "spi0"; -+ pins = "gpio52", "gpio53"; -+ bias-pull-up; -+ }; -+ }; -+ -+ rp1_eth: ethernet@100000 { -+ reg = <0xc0 0x40100000 0x0 0x4000>; -+ compatible = "cdns,macb"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ interrupts = ; -+ clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>; -+ clock-names = "pclk", "hclk", "tsu_clk"; -+ phy-mode = "rgmii-id"; -+ cdns,aw2w-max-pipe = /bits/ 8 <8>; -+ cdns,ar2r-max-pipe = /bits/ 8 <8>; -+ cdns,use-aw2b-fill; -+ local-mac-address = [00 00 00 00 00 00]; -+ status = "disabled"; -+ }; -+ -+ rp1_csi0: csi@110000 { -+ compatible = "raspberrypi,rp1-cfe"; -+ reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address -+ <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address -+ <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address -+ <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address -+ -+ // interrupts must match rp1_pisp_fe setup -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; -+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; -+ assigned-clock-rates = <25000000>; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ rp1_csi1: csi@128000 { -+ compatible = "raspberrypi,rp1-cfe"; -+ reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address -+ <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address -+ <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address -+ <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address -+ -+ // interrupts must match rp1_pisp_fe setup -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; -+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; -+ assigned-clock-rates = <25000000>; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ rp1_mmc0: mmc@180000 { -+ reg = <0xc0 0x40180000 0x0 0x100>; -+ compatible = "raspberrypi,rp1-dwcmshc"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core -+ &rp1_clocks RP1_CLK_SDIO_TIMER -+ &rp1_sdio_clk0>; -+ clock-names = "bus", "core", "timeout", "sdio"; -+ /* Bank 0 VDDIO is fixed */ -+ no-1-8-v; -+ bus-width = <4>; -+ vmmc-supply = <&rp1_vdd_3v3>; -+ broken-cd; -+ status = "disabled"; -+ }; -+ -+ rp1_mmc1: mmc@184000 { -+ reg = <0xc0 0x40184000 0x0 0x100>; -+ compatible = "raspberrypi,rp1-dwcmshc"; -+ interrupts = ; -+ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core -+ &rp1_clocks RP1_CLK_SDIO_TIMER -+ &rp1_sdio_clk1>; -+ clock-names = "bus", "core", "timeout", "sdio"; -+ bus-width = <4>; -+ vmmc-supply = <&rp1_vdd_3v3>; -+ /* Nerf SDR speeds */ -+ sdhci-caps-mask = <0x3 0x0>; -+ broken-cd; -+ status = "disabled"; -+ }; -+ -+ rp1_dma: dma@188000 { -+ reg = <0xc0 0x40188000 0x0 0x1000>; -+ compatible = "snps,axi-dma-1.01a"; -+ interrupts = ; -+ clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>; -+ clock-names = "core-clk", "cfgr-clk"; -+ -+ #dma-cells = <1>; -+ dma-channels = <8>; -+ snps,dma-masters = <1>; -+ snps,dma-targets = <64>; -+ snps,data-width = <4>; // (8 << 4) == 128 bits -+ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>; -+ snps,priority = <0 1 2 3 4 5 6 7>; -+ snps,axi-max-burst-len = <8>; -+ status = "disabled"; -+ }; -+ -+ rp1_usb0: usb@200000 { -+ reg = <0xc0 0x40200000 0x0 0x100000>; -+ compatible = "snps,dwc3"; -+ dr_mode = "host"; -+ usb3-lpm-capable; -+ snps,axi-pipe-limit = /bits/ 8 <8>; -+ snps,dis_rxdet_inp3_quirk; -+ snps,parkmode-disable-ss-quirk; -+ snps,parkmode-disable-hs-quirk; -+ snps,parkmode-disable-fsls-quirk; -+ snps,tx-max-burst = /bits/ 8 <8>; -+ snps,tx-thr-num-pkt = /bits/ 8 <2>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ rp1_usb1: usb@300000 { -+ reg = <0xc0 0x40300000 0x0 0x100000>; -+ compatible = "snps,dwc3"; -+ dr_mode = "host"; -+ usb3-lpm-capable; -+ snps,axi-pipe-limit = /bits/ 8 <8>; -+ snps,dis_rxdet_inp3_quirk; -+ snps,parkmode-disable-ss-quirk; -+ snps,parkmode-disable-hs-quirk; -+ snps,parkmode-disable-fsls-quirk; -+ snps,tx-max-burst = /bits/ 8 <8>; -+ snps,tx-thr-num-pkt = /bits/ 8 <2>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ rp1_dsi0: dsi@110000 { -+ compatible = "raspberrypi,rp1dsi"; -+ status = "disabled"; -+ reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI) -+ <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS) -+ <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG -+ -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, // required, config bus clock -+ <&rp1_clocks RP1_CLK_MIPI0_DPI>, // required, pixel clock -+ <&clksrc_mipi0_dsi_byteclk>, // internal, parent for divide -+ <&clk_xosc>; // hardwired to DSI "refclk" -+ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; -+ -+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, -+ <&rp1_clocks RP1_CLK_MIPI0_DPI>; -+ assigned-clock-rates = <25000000>; -+ assigned-clock-parents = <0>, <&clksrc_mipi0_dsi_byteclk>; -+ }; -+ -+ rp1_dsi1: dsi@128000 { -+ compatible = "raspberrypi,rp1dsi"; -+ status = "disabled"; -+ reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI) -+ <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS) -+ <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG -+ -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, // required, config bus clock -+ <&rp1_clocks RP1_CLK_MIPI1_DPI>, // required, pixel clock -+ <&clksrc_mipi1_dsi_byteclk>, // internal, parent for divide -+ <&clk_xosc>; // hardwired to DSI "refclk" -+ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk"; -+ -+ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, -+ <&rp1_clocks RP1_CLK_MIPI1_DPI>; -+ assigned-clock-rates = <25000000>; -+ assigned-clock-parents = <0>, <&clksrc_mipi1_dsi_byteclk>; -+ }; -+ -+ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */ -+ /* config.txt should enable one or other using dtparam=vec or an overlay. */ -+ rp1_vec: vec@144000 { -+ compatible = "raspberrypi,rp1vec"; -+ status = "disabled"; -+ reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC -+ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG -+ -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_VEC>; -+ -+ assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>, -+ <&rp1_clocks RP1_PLL_VIDEO_SEC>, -+ <&rp1_clocks RP1_CLK_VEC>; -+ assigned-clock-rates = <1188000000>, -+ <108000000>, -+ <108000000>; -+ assigned-clock-parents = <0>, -+ <&rp1_clocks RP1_PLL_VIDEO_CORE>, -+ <&rp1_clocks RP1_PLL_VIDEO_SEC>; -+ }; -+ -+ rp1_dpi: dpi@148000 { -+ compatible = "raspberrypi,rp1dpi"; -+ status = "disabled"; -+ reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI -+ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG -+ -+ interrupts = ; -+ -+ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock -+ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and -+ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control -+ clock-names = "dpiclk", "plldiv", "pllcore"; -+ -+ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>; -+ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>; -+ }; -+ }; -+}; -+ -+&clocks { -+ clk_xosc: clk_xosc { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "xosc"; -+ clock-frequency = <50000000>; -+ }; -+ macb_pclk: macb_pclk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "pclk"; -+ clock-frequency = <200000000>; -+ }; -+ macb_hclk: macb_hclk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "hclk"; -+ clock-frequency = <200000000>; -+ }; -+ sdio_src: sdio_src { -+ // 400 MHz on FPGA. PLL sys VCO on asic -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "src"; -+ clock-frequency = <1000000000>; -+ }; -+ sdhci_core: sdhci_core { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "core"; -+ clock-frequency = <50000000>; -+ }; -+ clksrc_mipi0_dsi_byteclk: clksrc_mipi0_dsi_byteclk { -+ // This clock is synthesized by MIPI0 D-PHY, when DSI is running. -+ // Its frequency is not known a priori (until a panel driver attaches) -+ // so assign a made-up frequency of 72MHz so it can be divided for DPI. -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "clksrc_mipi0_dsi_byteclk"; -+ clock-frequency = <72000000>; -+ }; -+ clksrc_mipi1_dsi_byteclk: clksrc_mipi1_dsi_byteclk { -+ // This clock is synthesized by MIPI1 D-PHY, when DSI is running. -+ // Its frequency is not known a priori (until a panel driver attaches) -+ // so assign a made-up frequency of 72MHz so it can be divided for DPI. -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-output-names = "clksrc_mipi1_dsi_byteclk"; -+ clock-frequency = <72000000>; -+ }; -+ /* GPIO derived clock sources. Each GPIO with a GPCLK function -+ * can drive its output from the respective GPCLK -+ * generator, and provide a clock source to other internal -+ * dividers. Add dummy sources here so that they can be overridden -+ * with overlays. -+ */ -+ clksrc_gp0: clksrc_gp0 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ #clock-cells = <0>; -+ clock-div = <1>; -+ clock-mult = <1>; -+ clocks = <&rp1_clocks RP1_CLK_GP0>; -+ clock-output-names = "clksrc_gp0"; -+ }; -+ clksrc_gp1: clksrc_gp1 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ #clock-cells = <0>; -+ clock-div = <1>; -+ clock-mult = <1>; -+ clocks = <&rp1_clocks RP1_CLK_GP1>; -+ clock-output-names = "clksrc_gp1"; -+ }; -+ clksrc_gp2: clksrc_gp2 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ clock-div = <1>; -+ clock-mult = <1>; -+ #clock-cells = <0>; -+ clocks = <&rp1_clocks RP1_CLK_GP2>; -+ clock-output-names = "clksrc_gp2"; -+ }; -+ clksrc_gp3: clksrc_gp3 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ clock-div = <1>; -+ clock-mult = <1>; -+ #clock-cells = <0>; -+ clocks = <&rp1_clocks RP1_CLK_GP3>; -+ clock-output-names = "clksrc_gp3"; -+ }; -+ clksrc_gp4: clksrc_gp4 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ #clock-cells = <0>; -+ clock-div = <1>; -+ clock-mult = <1>; -+ clocks = <&rp1_clocks RP1_CLK_GP4>; -+ clock-output-names = "clksrc_gp4"; -+ }; -+ clksrc_gp5: clksrc_gp5 { -+ status = "disabled"; -+ compatible = "fixed-factor-clock"; -+ #clock-cells = <0>; -+ clock-div = <1>; -+ clock-mult = <1>; -+ clocks = <&rp1_clocks RP1_CLK_GP5>; -+ clock-output-names = "clksrc_gp5"; -+ }; -+}; -+ -+/ { -+ rp1_vdd_3v3: rp1_vdd_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "vdd-3v3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ }; -+}; + /* The oscillator is the root of the clock tree. */ + clk_osc: clk-osc { + compatible = "fixed-clock"; diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile new file mode 100644 -index 000000000000..86e499122ca9 +index 000000000000..6b60068b125c --- /dev/null +++ b/arch/arm/boot/dts/overlays/Makefile -@@ -0,0 +1,336 @@ +@@ -0,0 +1,347 @@ +# Overlays for the Raspberry Pi platform + +dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb hat_map.dtb @@ -16095,8 +12061,11 @@ index 000000000000..86e499122ca9 + gpio-no-irq.dtbo \ + gpio-poweroff.dtbo \ + gpio-shutdown.dtbo \ ++ hd44780-i2c-lcd.dtbo \ + hd44780-lcd.dtbo \ + hdmi-backlight-hwhack-gpio.dtbo \ ++ hifiberry-adc.dtbo \ ++ hifiberry-adc8x.dtbo \ + hifiberry-amp.dtbo \ + hifiberry-amp100.dtbo \ + hifiberry-amp3.dtbo \ @@ -16137,6 +12106,7 @@ index 000000000000..86e499122ca9 + i2c6.dtbo \ + i2s-dac.dtbo \ + i2s-gpio28-31.dtbo \ ++ i2s-master-dac.dtbo \ + ilitek251x.dtbo \ + imx219.dtbo \ + imx258.dtbo \ @@ -16146,6 +12116,8 @@ index 000000000000..86e499122ca9 + imx378.dtbo \ + imx462.dtbo \ + imx477.dtbo \ ++ imx500.dtbo \ ++ imx500-pi5.dtbo \ + imx519.dtbo \ + imx708.dtbo \ + interludeaudio-analog.dtbo \ @@ -16202,6 +12174,7 @@ index 000000000000..86e499122ca9 + pcf857x.dtbo \ + pcie-32bit-dma.dtbo \ + pcie-32bit-dma-pi5.dtbo \ ++ pciex1-compat-pi5.dtbo \ + pibell.dtbo \ + pifacedigital.dtbo \ + pifi-40.dtbo \ @@ -16210,6 +12183,7 @@ index 000000000000..86e499122ca9 + pifi-mini-210.dtbo \ + piglow.dtbo \ + pineboards-hat-ai.dtbo \ ++ pineboards-hatdrive-poe-plus.dtbo \ + piscreen.dtbo \ + piscreen2r.dtbo \ + pisound.dtbo \ @@ -16222,6 +12196,7 @@ index 000000000000..86e499122ca9 + proto-codec.dtbo \ + pwm.dtbo \ + pwm-2chan.dtbo \ ++ pwm-gpio.dtbo \ + pwm-ir-tx.dtbo \ + pwm1.dtbo \ + qca7000.dtbo \ @@ -16287,6 +12262,7 @@ index 000000000000..86e499122ca9 + ssd1306-spi.dtbo \ + ssd1331-spi.dtbo \ + ssd1351-spi.dtbo \ ++ sunfounder-pipower3.dtbo \ + sunfounder-pironman5.dtbo \ + superaudioboard.dtbo \ + sx150x.dtbo \ @@ -16323,6 +12299,7 @@ index 000000000000..86e499122ca9 + vc4-kms-dsi-ili9881-7inch.dtbo \ + vc4-kms-dsi-lt070me05000.dtbo \ + vc4-kms-dsi-lt070me05000-v2.dtbo \ ++ vc4-kms-dsi-waveshare-800x480.dtbo \ + vc4-kms-dsi-waveshare-panel.dtbo \ + vc4-kms-kippah-7inch.dtbo \ + vc4-kms-v3d.dtbo \ @@ -16349,10 +12326,10 @@ index 000000000000..86e499122ca9 +clean-files := *.dtbo diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README new file mode 100644 -index 000000000000..7cb552f4784a +index 000000000000..5c6344eb6f98 --- /dev/null +++ b/arch/arm/boot/dts/overlays/README -@@ -0,0 +1,5389 @@ +@@ -0,0 +1,5516 @@ +Introduction +============ + @@ -16526,21 +12503,21 @@ index 000000000000..7cb552f4784a + button_debounce Set the debounce delay (in ms) on the power/ + shutdown button (default 50ms) + -+ cam0_reg Enables CAM 0 regulator. -+ Only required on CM1 & 3. ++ cam0_reg Controls CAM 0 regulator. ++ Disabled by default on CM1 & 3. ++ Enabled by default on all other boards. + + cam0_reg_gpio Set GPIO for CAM 0 regulator. -+ Default 31 on CM1, 3, and 4S. -+ Default of GPIO expander 5 on CM4, but override -+ switches to normal GPIO. ++ NB override switches to the normal GPIO driver, ++ even if the original was on the GPIO expander. + -+ cam1_reg Enables CAM 1 regulator. -+ Only required on CM1 & 3. ++ cam1_reg Controls CAM 1 regulator. ++ Disabled by default on CM1 & 3. ++ Enabled by default on all other boards. + + cam1_reg_gpio Set GPIO for CAM 1 regulator. -+ Default 3 on CM1, 3, and 4S. -+ Default of GPIO expander 5 on CM4, but override -+ switches to normal GPIO. ++ NB override switches to the normal GPIO driver, ++ even if the original was on the GPIO expander. + + cam0_sync Enable a GPIO to reflect frame sync from CSI0, + going high on frame start, and low on frame end. @@ -16733,9 +12710,9 @@ index 000000000000..7cb552f4784a + non-lite SKU of CM4). + (default "on") + -+ sd_cqe Use to enable Command Queueing on the SD -+ interface for faster Class A2 card performance -+ (Pi 5 only, default "off") ++ sd_cqe Set to "off" to disable Command Queueing if you ++ have an incompatible Class A2 SD card ++ (Pi 5 only, default "on") + + sd_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz @@ -18060,6 +14037,33 @@ index 000000000000..7cb552f4784a + (default 100) + + ++Name: hd44780-i2c-lcd ++Info: Configures an HD44780 compatible LCD display connected via a PCF8574 as ++ is often found as a backpack interface for these displays. ++Load: dtoverlay=hd44780-i2c-lcd,= ++Params: addr I2C address of PCF8574 ++ pin_d4 GPIO pin for data pin D4 (default 4) ++ ++ pin_d5 GPIO pin for data pin D5 (default 5) ++ ++ pin_d6 GPIO pin for data pin D6 (default 6) ++ ++ pin_d7 GPIO pin for data pin D7 (default 7) ++ ++ pin_en GPIO pin for "Enable" (default 2) ++ ++ pin_rs GPIO pin for "Register Select" (default 0) ++ ++ pin_rw GPIO pin for R/W select (default 1) ++ ++ pin_bl GPIO pin for enabling/disabling the display ++ backlight. (default 3) ++ ++ display_height Height of the display in characters (default 2) ++ ++ display_width Width of the display in characters (default 16) ++ ++ +Name: hd44780-lcd +Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for + data, 2 gpio pins for enable and register select and 1 optional pin @@ -18080,9 +14084,9 @@ index 000000000000..7cb552f4784a + pin_bl Optional pin for enabling/disabling the + display backlight. (default disabled) + -+ display_height Height of the display in characters ++ display_height Height of the display in characters (default 2) + -+ display_width Width of the display in characters ++ display_width Width of the display in characters (default 16) + + +Name: hdmi-backlight-hwhack-gpio @@ -18099,6 +14103,19 @@ index 000000000000..7cb552f4784a + expects a high to switch it on. + + ++Name: hifiberry-adc ++Info: Configures the HifiBerry ADC audio card ++Load: dtoverlay=hifiberry-adc,= ++Params: leds_off If set to 'true' the onboard indicator LED ++ is switched off at all times. ++ ++ ++Name: hifiberry-adc8x ++Info: Configures the HifiBerry ADC8X audio card (only on Pi5) ++Load: dtoverlay=hifiberry-adc8x ++Params: ++ ++ +Name: hifiberry-amp +Info: Configures the HifiBerry Amp and Amp+ audio cards +Load: dtoverlay=hifiberry-amp @@ -18961,6 +14978,12 @@ index 000000000000..7cb552f4784a +Params: + + ++Name: i2s-master-dac ++Info: Configures a generic I2S DAC soundcard that acts as a clock master. ++Load: dtoverlay=i2s-master-dac ++Params: ++ ++ +Name: ilitek251x +Info: Enables I2C connected Ilitek 251x multiple touch controller using + GPIO 4 (pin 7 on GPIO header) for interrupt. @@ -19133,6 +15156,27 @@ index 000000000000..7cb552f4784a + sync-sink Configure as vsync sink + + ++Name: imx500 ++Info: Sony IMX500 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. ++Load: dtoverlay=imx500,= ++Params: rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ media-controller Configure use of Media Controller API for ++ configuring the sensor (default on) ++ cam0 Adopt the default configuration for CAM0 on a ++ Compute Module (CSI0, i2c_vc, and cam0_reg). ++ bypass-cache Do save blocks of data to flash when using ++ rp2040-gpio-bridge for SPI transfers. ++ ++ ++Name: imx500-pi5 ++Info: See imx500 (this is the Pi 5 version) ++ ++ +Name: imx519 +Info: Sony IMX519 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi @@ -19895,6 +15939,18 @@ index 000000000000..7cb552f4784a +Load: dtoverlay=pcie-32bit-dma-pi5 +Params: + ++ ++Name: pciex1-compat-pi5 ++Info: Compatibility features for pciex1 on Pi 5. ++Load: dtoverlay=pciex1-compat-pi5,= ++Params: l1ss Enable ASPM L1 sub-state support ++ no-l0s Disable ASPM L0s ++ no-mip Revert to the MSI target in the RC, instead of ++ the MSI-MIP peripheral. Use if a) more than 8 ++ interrupt vectors are required or b) the EP ++ requires DMA and MSI addresses to be 32bit. ++ ++ +[ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ] + + @@ -19979,6 +16035,12 @@ index 000000000000..7cb552f4784a +Params: + + ++Name: pineboards-hatdrive-poe-plus ++Info: Configures the Pineboards HatDrive! PoE+ ++Load: dtoverlay=pineboards-hatdrive-poe-plus ++Params: ++ ++ +Name: piscreen +Info: PiScreen display by OzzMaker.com +Load: dtoverlay=piscreen,= @@ -19995,6 +16057,12 @@ index 000000000000..7cb552f4784a + drm Select the DRM/KMS driver instead of the FBTFT + one + ++ invx Touchscreen inverted x axis ++ ++ invy Touchscreen inverted y axis ++ ++ swapxy Touchscreen swapped x y axis ++ + +Name: piscreen2r +Info: PiScreen 2 with resistive TP display by OzzMaker.com @@ -20167,6 +16235,12 @@ index 000000000000..7cb552f4784a + clock PWM clock frequency (informational) + + ++Name: pwm-gpio ++Info: Configures the software PWM GPIO driver ++Load: dtoverlay=pwm-gpio,= ++Params: gpio Output pin (default 4) ++ ++ +Name: pwm-ir-tx +Info: Use GPIO pin as pwm-assisted infrared transmitter output. + This is an alternative to "gpio-ir-tx". pwm-ir-tx makes use @@ -21036,11 +17110,17 @@ index 000000000000..7cb552f4784a + reset_pin GPIO pin for RESET (default 25) + + ++Name: sunfounder-pipower3 ++Info: Overlay for SunFounder PiPower 3 ++Load: dtoverlay=sunfounder-pipower3,= ++Params: poweroff_pin Change poweroff pin (default 26) ++ ++ +Name: sunfounder-pironman5 +Info: Overlay for SunFounder Pironman 5 +Load: dtoverlay=sunfounder-pironman5,= +Params: ir Enable IR or not (on or off, default on) -+ ir_pins Change IR receiver pin (default 12) ++ ir_pins Change IR receiver pin (default 13) + + +Name: superaudioboard @@ -21343,6 +17423,10 @@ index 000000000000..7cb552f4784a + Set the default brightness. Normal range 1-16. + (default 16). + rotate Display rotation {0,90,180,270} (default 0) ++ rgb-order Allow override of RGB order from DPI. ++ Options for vc4 are "rgb", "bgr", "grb", and ++ "brg". Other values will be ignored. ++ + + +Name: vc4-kms-dpi-hyperpixel2r @@ -21502,6 +17586,23 @@ index 000000000000..7cb552f4784a +Params: + + ++Name: vc4-kms-dsi-waveshare-800x480 ++Info: Enable the Waveshare 4.3" 800x480 DSI screen. ++ It tries to look like the Pi 7" display, but won't accept some of the ++ timings. ++ Includes the edt-ft5406 for the touchscreen element. ++ Requires vc4-kms-v3d to be loaded. ++Load: dtoverlay=vc4-kms-dsi-waveshare-800x480,= ++Params: sizex Touchscreen size x (default 800) ++ sizey Touchscreen size y (default 480) ++ invx Touchscreen inverted x axis ++ invy Touchscreen inverted y axis ++ swapxy Touchscreen swapped x y axis ++ disable_touch Disables the touch screen overlay driver ++ dsi0 Use DSI0 and i2c_csi_dsi0 (rather than ++ the default DSI1 and i2c_csi_dsi). ++ ++ +Name: vc4-kms-dsi-waveshare-panel +Info: Enable a Waveshare DSI touchscreen + Includes the Goodix driver for the touchscreen element. @@ -21518,6 +17619,9 @@ index 000000000000..7cb552f4784a + 3_4_inch 3.4" 800x800 round + 4_0_inch 4.0" 480x800 + 4_0_inchC 4.0" 720x720 ++ 5_0_inch 5.0" 720x1280 ++ 6_25_inch 6.25" 720x1560 ++ 8_8_inch 8.8" 480x1920 + 7_0_inchC 7.0" C 1024x600 + 7_9_inch 7.9" 400x1280 + 8_0_inch 8.0" 1280x800 @@ -24119,7 +20223,7 @@ index 000000000000..8fc22587e69c +}; diff --git a/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts new file mode 100644 -index 000000000000..8f9c6a887064 +index 000000000000..3ce844f4f113 --- /dev/null +++ b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts @@ -0,0 +1,75 @@ @@ -24166,7 +20270,7 @@ index 000000000000..8f9c6a887064 + fragment@4 { + target = <&vc4>; + __overlay__ { -+ compatible = "brcm,bcm2712d0-vc6"; ++ compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6"; + }; + }; + @@ -29245,13 +25349,25 @@ index 000000000000..da148064aedd +}; diff --git a/arch/arm/boot/dts/overlays/hat_map.dts b/arch/arm/boot/dts/overlays/hat_map.dts new file mode 100644 -index 000000000000..cb96b680cb4f +index 000000000000..0b5d902e85b8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/hat_map.dts -@@ -0,0 +1,98 @@ +@@ -0,0 +1,124 @@ +/dts-v1/; + +/ { ++ hailo-8 { ++ product = "Raspberry Pi AI Hat, Model Hailo-8"; ++ vendor = "Hailo Technologies"; ++ overlay = "none,pciex1,pciex1_gen=3"; ++ }; ++ ++ hailo-8l { ++ product = "Raspberry Pi AI Hat, Model Hailo-8L"; ++ vendor = "Hailo Technologies"; ++ overlay = "none,pciex1,pciex1_gen=3"; ++ }; ++ + hifiberry-amp100-1 { + uuid = [ 5eb863b8 12f9 41ad 978f 4cee1b3eca62 ]; + overlay = "hifiberry-amp100"; @@ -29346,6 +25462,83 @@ index 000000000000..cb96b680cb4f + uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ]; + overlay = "recalboxrgbdual"; + }; ++ ++ sensehat-v1 { ++ product = "Sense HAT"; ++ vendor = "Raspberry Pi"; ++ pver = < 0x0001 >; ++ overlay = "rpi-sense"; ++ }; ++ ++ sensehat-v2 { ++ product = "Sense HAT"; ++ vendor = "Raspberry Pi"; ++ pver = < 0x0002 >; ++ overlay = "rpi-sense-v2"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts b/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts +new file mode 100644 +index 000000000000..36fcf049ffbf +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hd44780-i2c-lcd-overlay.dts +@@ -0,0 +1,57 @@ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c_arm>; ++ __overlay__ { ++ status = "okay"; ++ ++ pcf857x: pcf857x@27 { ++ compatible = "nxp,pcf8574"; ++ reg = <0x27>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ lcd_screen: auxdisplay { ++ compatible = "hit,hd44780"; ++ ++ data-gpios = <&pcf857x 4 0>, ++ <&pcf857x 5 0>, ++ <&pcf857x 6 0>, ++ <&pcf857x 7 0>; ++ enable-gpios = <&pcf857x 2 0>; ++ rs-gpios = <&pcf857x 0 0>; ++ rw-gpios = <&pcf857x 1 0>; ++ backlight-gpios = <&pcf857x 3 0>; ++ ++ display-width-chars = <16>; ++ display-height-chars = <2>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ pin_d4 = <&lcd_screen>,"data-gpios:4"; ++ pin_d5 = <&lcd_screen>,"data-gpios:16"; ++ pin_d6 = <&lcd_screen>,"data-gpios:28"; ++ pin_d7 = <&lcd_screen>,"data-gpios:40"; ++ pin_en = <&lcd_screen>,"enable-gpios:4"; ++ pin_rs = <&lcd_screen>,"rs-gpios:4"; ++ pin_rw = <&lcd_screen>,"rw-gpios:4"; ++ pin_bl = <&lcd_screen>,"backlight-gpios:4"; ++ display_height = <&lcd_screen>,"display-height-chars:0"; ++ display_width = <&lcd_screen>,"display-width-chars:0"; ++ addr = <&pcf857x>,"reg:0"; ++ }; ++ +}; diff --git a/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts b/arch/arm/boot/dts/overlays/hd44780-lcd-overlay.dts new file mode 100644 @@ -29452,6 +25645,113 @@ index 000000000000..50b9a2665c80 + active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts +new file mode 100644 +index 000000000000..2658f3242556 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Definitions for HiFiBerry ADC, no onboard clocks ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ hb_adc: pcm186x@4a { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm1863"; ++ reg = <0x4a>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sound>; ++ hifiberry_adc: __overlay__ { ++ compatible = "hifiberry,hifiberry-adc"; ++ audio-codec = <&hb_adc>; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ leds_off = <&hifiberry_adc>,"hifiberry-adc,leds_off?"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts +new file mode 100644 +index 000000000000..e0432115dc39 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for HiFiBerry ADC8x ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ rp1_i2s0_adc8x: rp1_i2s0_adc8x { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio20", ++ "gpio22", "gpio24", "gpio26"; ++ bias-disable; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s_clk_producer>; ++ __overlay__ { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_adc8x>; ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ dummy-codec { ++ #sound-dai-cells = <0>; ++ compatible = "snd-soc-dummy"; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "hifiberry,hifiberry-adc8x"; ++ i2s-controller = <&i2s_clk_producer>; ++ status = "okay"; ++ }; ++ }; ++ ++}; diff --git a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts new file mode 100644 index 000000000000..667cd2601806 @@ -31374,7 +27674,7 @@ index 000000000000..b8dfbd56d121 +}; diff --git a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi new file mode 100644 -index 000000000000..d2b54fe23339 +index 000000000000..8638123336ba --- /dev/null +++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi @@ -0,0 +1,367 @@ @@ -31734,7 +28034,7 @@ index 000000000000..d2b54fe23339 + <&rv3028>,"trickle-resistor-ohms:0", + <&rv3032>,"trickle-resistor-ohms:0", + <&rv1805>,"abracon,tc-resistor:0", -+ <&bq32000>,"abracon,tc-resistor:0"; ++ <&bq32000>,"trickle-resistor-ohms:0"; + trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0"; + backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0"; + wakeup-source = <&ds1339>,"wakeup-source?", @@ -32979,6 +29279,62 @@ index 000000000000..cf43094c6ff4 + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts b/arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts +new file mode 100644 +index 000000000000..8b46067858d7 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts +@@ -0,0 +1,50 @@ ++// Definitions for a generic I2S DAC that acts as clock master on the bus. ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s_clk_consumer>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ codec_bare: codec_bare { ++ compatible = "linux,spdif-dit"; ++ #sound-dai-cells = <0>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "simple-audio-card"; ++ i2s-controller = <&i2s_clk_consumer>; ++ status = "okay"; ++ ++ simple-audio-card,name = "i2s-master-dac"; ++ simple-audio-card,format = "i2s"; ++ ++ simple-audio-card,bitclock-master = <&snd_codec>; ++ simple-audio-card,frame-master = <&snd_codec>; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&i2s_clk_consumer>; ++ dai-tdm-slot-num = <2>; ++ dai-tdm-slot-width = <32>; ++ }; ++ ++ snd_codec: simple-audio-card,codec { ++ sound-dai = <&codec_bare>; ++ }; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts b/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts new file mode 100644 index 000000000000..551aba591d26 @@ -33892,6 +30248,301 @@ index 000000000000..a0c154c2a11f + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/imx500-overlay.dts b/arch/arm/boot/dts/overlays/imx500-overlay.dts +new file mode 100644 +index 000000000000..b8d76feb259a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts +@@ -0,0 +1,122 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX500 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@2 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <300000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx500.dtsi" ++ #include "rpi-rp2040-gpio-bridge.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ spi_frag: fragment@102 { ++ target = <&spi_bridgedev0>; ++ __overlay__ { ++ compatible = "sony,imx500"; ++ }; ++ }; ++ ++ chosen_frag: fragment@103 { ++ target = <&chosen>; ++ __overlay__ { ++ core_freq_fixed; ++ }; ++ }; ++ ++ fragment@104 { ++ target-path = "/clocks"; ++ __overlay__ { ++ clk_aicam: clk-aicam1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_aicam_gated: clk-aicam-gated1 { ++ compatible = "gpio-gate-clock"; ++ clocks = <&clk_aicam>; ++ #clock-cells = <0>; ++ enable-gpios = <&spi_bridge 21 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&spi_bridge>, "power-supply:0=",<&cam0_reg>, ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&clk_aicam>,"name=clk-aicam0", ++ <&clk_aicam_gated>,"name=clk-aicam-gated0"; ++ bypass-cache = <&spi_bridge>,"bypass-cache?"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++ led-gpios = <&spi_bridge 19 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; ++ clocks = <&clk_aicam_gated>; ++ spi = <&spi_bridgedev0>; ++}; ++ ++&spi_bridge { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts +new file mode 100644 +index 000000000000..8ad4f0cd1c7b +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts +@@ -0,0 +1,127 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX500 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@2 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <300000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx500.dtsi" ++ #include "rpi-rp2040-gpio-bridge.dtsi" ++ }; ++ }; ++ ++ csi_frag: fragment@101 { ++ target = <&csi1>; ++ csi: __overlay__ { ++ status = "okay"; ++ brcm,media-controller; ++ ++ port { ++ csi_ep: endpoint { ++ remote-endpoint = <&cam_endpoint>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ }; ++ }; ++ }; ++ }; ++ ++ spi_frag: fragment@102 { ++ target = <&spi_bridge>; ++ spi_frag_overlay: __overlay__ { ++ fast_xfer_requires_i2c_lock = <1>; ++ fast_xfer_recv_gpio_base = <11>; ++ fast_xfer-gpios = <&rp1_gpio 40 0>, // CD1_SDA (used as data) ++ <&rp1_gpio 48 0>; // CD1_IO1_MICDAT1 (clock) ++ }; ++ }; ++ ++ spi_bridge_frag: fragment@103 { ++ target = <&spi_bridgedev0>; ++ __overlay__ { ++ compatible = "sony,imx500"; ++ }; ++ }; ++ ++ fragment@104 { ++ target-path = "/clocks"; ++ __overlay__ { ++ clk_aicam: clk-aicam1 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_aicam_gated: clk-aicam-gated1 { ++ compatible = "gpio-gate-clock"; ++ clocks = <&clk_aicam>; ++ #clock-cells = <0>; ++ enable-gpios = <&spi_bridge 21 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ rotation = <&cam_node>,"rotation:0"; ++ orientation = <&cam_node>,"orientation:0"; ++ media-controller = <&csi>,"brcm,media-controller?"; ++ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&csi_frag>, "target:0=",<&csi0>, ++ <&spi_frag_overlay>, "fast_xfer-gpios:4=38", // CD0_SDA (data) ++ <&spi_frag_overlay>, "fast_xfer-gpios:16=35", // CD0_IO1_MICDAT0 (clock) ++ <&spi_bridge>, "power-supply:0=",<&cam0_reg>, ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&cam_node>, "VANA-supply:0=",<&cam0_reg>, ++ <&clk_aicam>,"name=clk-aicam0", ++ <&clk_aicam_gated>,"name=clk-aicam-gated0"; ++ bypass-cache = <&spi_bridge>,"bypass-cache?"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++ led-gpios = <&spi_bridge 19 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&spi_bridge 20 GPIO_ACTIVE_HIGH>; ++ clocks = <&clk_aicam_gated>; ++ spi = <&spi_bridgedev0>; ++}; ++ ++&spi_bridge { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +diff --git a/arch/arm/boot/dts/overlays/imx500.dtsi b/arch/arm/boot/dts/overlays/imx500.dtsi +new file mode 100644 +index 000000000000..a931aa9941e6 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx500.dtsi +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++cam_node: imx500@1a { ++ reg = <0x1a>; ++ compatible = "sony,imx500"; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "inck"; ++ ++ vana-supply = <&cam1_reg>; /* 2.7v */ ++ vdig-supply = <&cam_dummy_reg>; /* 0.84v */ ++ vif-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ++ reset-gpios = <&gpio 255 GPIO_ACTIVE_HIGH>; ++ ++ rotation = <0>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <444000000>; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/imx519-overlay.dts b/arch/arm/boot/dts/overlays/imx519-overlay.dts new file mode 100644 index 000000000000..f572634836b8 @@ -35444,7 +32095,7 @@ index 000000000000..e3f56608c643 +}; diff --git a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts new file mode 100644 -index 000000000000..d77690b17711 +index 000000000000..0f9e89484c55 --- /dev/null +++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts @@ -0,0 +1,103 @@ @@ -35484,6 +32135,8 @@ index 000000000000..d77690b17711 + target = <&mcp23017>; + mcp23017_irq: __overlay__ { + #interrupt-cells=<2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mcp23017_pins>; + interrupt-parent = <&gpio>; + interrupts = <4 2>; + interrupt-controller; @@ -35499,8 +32152,6 @@ index 000000000000..d77690b17711 + + mcp23017: mcp@20 { + compatible = "microchip,mcp23017"; -+ pinctrl-name = "default"; -+ pinctrl-0 = <&mcp23017_pins>; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; @@ -39229,10 +35880,10 @@ index 000000000000..7df43bc6ef39 +}; diff --git a/arch/arm/boot/dts/overlays/overlay_map.dts b/arch/arm/boot/dts/overlays/overlay_map.dts new file mode 100644 -index 000000000000..c2643b485bbc +index 000000000000..2ddf4c7f4323 --- /dev/null +++ b/arch/arm/boot/dts/overlays/overlay_map.dts -@@ -0,0 +1,493 @@ +@@ -0,0 +1,514 @@ +/dts-v1/; + +/ { @@ -39283,6 +35934,10 @@ index 000000000000..c2643b485bbc + bcm2712; + }; + ++ hifiberry-adc8x { ++ bcm2712; ++ }; ++ + hifiberry-dac8x { + bcm2712; + }; @@ -39353,6 +36008,16 @@ index 000000000000..c2643b485bbc + bcm2711; + }; + ++ imx500 { ++ bcm2835; ++ bcm2711; ++ bcm2712 = "imx500-pi5"; ++ }; ++ ++ imx500-pi5 { ++ bcm2712; ++ }; ++ + lirc-rpi { + deprecated = "use gpio-ir"; + }; @@ -39431,6 +36096,10 @@ index 000000000000..c2643b485bbc + bcm2712; + }; + ++ pcie-compat-pi5 { ++ bcm2712; ++ }; ++ + pi3-act-led { + renamed = "act-led"; + }; @@ -39464,10 +36133,12 @@ index 000000000000..c2643b485bbc + ramoops { + bcm2835; + bcm2711 = "ramoops-pi4"; ++ bcm2712 = "ramoops-pi4"; + }; + + ramoops-pi4 { + bcm2711; ++ bcm2712; + }; + + rpi-cirrus-wm5102 { @@ -39498,6 +36169,7 @@ index 000000000000..c2643b485bbc + sdio { + bcm2835; + bcm2711; ++ bcm2712 = "sdio-pi5"; + }; + + sdio-1bit { @@ -40176,6 +36848,52 @@ index 000000000000..f9908494f101 + }; + +}; +diff --git a/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts b/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts +new file mode 100644 +index 000000000000..a97b6c12ab35 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts +@@ -0,0 +1,40 @@ ++/* ++ * Various feature switches for the 1-lane PCIe controller on Pi 5 ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ /* Enable L1 sub-state support */ ++ fragment@0 { ++ target = <&pciex1>; ++ __dormant__ { ++ brcm,enable-l1ss; ++ }; ++ }; ++ ++ /* Disable ASPM L0s */ ++ fragment@1 { ++ target = <&pciex1>; ++ __dormant__ { ++ aspm-no-l0s; ++ }; ++ }; ++ ++ /* Use RC MSI target instead of MIP MSIx target */ ++ fragment@2 { ++ target = <&pciex1>; ++ __dormant__ { ++ msi-parent = <&pciex1>; ++ }; ++ }; ++ ++ __overrides__ { ++ l1ss = <0>, "+0"; ++ no-l0s = <0>, "+1"; ++ no-mip = <0>, "+2"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/pibell-overlay.dts b/arch/arm/boot/dts/overlays/pibell-overlay.dts new file mode 100644 index 000000000000..99d4b6d97969 @@ -40754,12 +37472,37 @@ index 000000000000..8160272f4705 + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts b/arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts +new file mode 100644 +index 000000000000..77b8e0d3be31 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts +@@ -0,0 +1,19 @@ ++/* ++ * Device Tree overlay for Pineboards HatDrive! PoE+. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2712"; ++ ++ fragment@0 { ++ target-path = "/chosen"; ++ __overlay__ { ++ power: power { ++ hat_current_supply = <5000>; ++ }; ++ }; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/piscreen-overlay.dts b/arch/arm/boot/dts/overlays/piscreen-overlay.dts new file mode 100644 -index 000000000000..29bcd41f39cf +index 000000000000..bd389c8a5e51 --- /dev/null +++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts -@@ -0,0 +1,107 @@ +@@ -0,0 +1,110 @@ +/* + * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker + * @@ -40865,6 +37608,9 @@ index 000000000000..29bcd41f39cf + xohms = <&piscreen_ts>,"ti,x-plate-ohms;0"; + drm = <&piscreen>,"compatible=waveshare,rpi-lcd-35", + <&piscreen>,"reset-gpios:8=",; ++ invx = <&piscreen_ts>,"touchscreen-inverted-x?"; ++ invy = <&piscreen_ts>,"touchscreen-inverted-y?"; ++ swapxy = <&piscreen_ts>,"touchscreen-swapped-x-y!"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts @@ -41725,6 +38471,50 @@ index 000000000000..823c8b4126d1 + clock = <&frag1>,"assigned-clock-rates:0"; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/pwm-gpio-overlay.dts b/arch/arm/boot/dts/overlays/pwm-gpio-overlay.dts +new file mode 100644 +index 000000000000..f5a1fb38e257 +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pwm-gpio-overlay.dts +@@ -0,0 +1,38 @@ ++// Device tree overlay for software GPIO PWM. ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ pwm_gpio_pins: pwm_gpio_pins@4 { ++ brcm,pins = <4>; /* gpio 4 */ ++ brcm,function = <1>; /* output */ ++ brcm,pull = <0>; /* pull-none */ ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ pwm_gpio: pwm_gpio@4 { ++ compatible = "pwm-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_gpio_pins>; ++ gpios = <&gpio 4 0>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ gpio = <&pwm_gpio>,"gpios:4", ++ <&pwm_gpio_pins>,"brcm,pins:0", ++ /* modify reg values to allow multiple instantiation */ ++ <&pwm_gpio>,"reg:0", ++ <&pwm_gpio_pins>,"reg:0"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts b/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts new file mode 100644 index 000000000000..33597eb79729 @@ -42483,12 +39273,39 @@ index 000000000000..54deda2f18c3 + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; +}; +diff --git a/arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi b/arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi +new file mode 100644 +index 000000000000..2b7f670a1f6d +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-rp2040-gpio-bridge.dtsi +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++spi_bridge: spi@40 { ++ reg = <0x40>; ++ compatible = "raspberrypi,rp2040-gpio-bridge"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ power-supply = <&cam1_reg>; ++ ++ #gpio-cells = <2>; ++ gpio-controller; ++ ++ spi_bridgedev0: spidev@0{ ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <35000000>; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts new file mode 100644 -index 000000000000..89d8d2ea6b2e +index 000000000000..32e99b7effc8 --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts -@@ -0,0 +1,47 @@ +@@ -0,0 +1,69 @@ +// rpi-sense HAT +/dts-v1/; +/plugin/; @@ -42503,11 +39320,23 @@ index 000000000000..89d8d2ea6b2e + #size-cells = <0>; + status = "okay"; + -+ rpi-sense@46 { -+ compatible = "rpi,rpi-sense"; ++ sensehat@46 { ++ compatible = "raspberrypi,sensehat"; + reg = <0x46>; -+ keys-int-gpios = <&gpio 23 1>; ++ interrupt-parent = <&gpio>; + status = "okay"; ++ ++ display { ++ compatible = "raspberrypi,rpi-sense-fb"; ++ status = "okay"; ++ }; ++ joystick { ++ compatible = "raspberrypi,sensehat-joystick"; ++ interrupts = <23 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sensehat_pins>; ++ status = "okay"; ++ }; + }; + + lsm9ds1-magn@1c { @@ -42535,13 +39364,23 @@ index 000000000000..89d8d2ea6b2e + }; + }; + }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sensehat_pins: sensehat_pins { ++ brcm,pins = <23>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts new file mode 100644 -index 000000000000..1b86c032259b +index 000000000000..c4fe97db52fb --- /dev/null +++ b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts -@@ -0,0 +1,47 @@ +@@ -0,0 +1,69 @@ +// rpi-sense HAT +/dts-v1/; +/plugin/; @@ -42556,11 +39395,23 @@ index 000000000000..1b86c032259b + #size-cells = <0>; + status = "okay"; + -+ rpi-sense@46 { -+ compatible = "rpi,rpi-sense"; ++ sensehat@46 { ++ compatible = "raspberrypi,sensehat"; + reg = <0x46>; -+ keys-int-gpios = <&gpio 23 1>; ++ interrupt-parent = <&gpio>; + status = "okay"; ++ ++ display { ++ compatible = "raspberrypi,rpi-sense-fb"; ++ status = "okay"; ++ }; ++ joystick { ++ compatible = "raspberrypi,sensehat-joystick"; ++ interrupts = <23 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sensehat_pins>; ++ status = "okay"; ++ }; + }; + + lsm9ds1-magn@1c { @@ -42588,6 +39439,16 @@ index 000000000000..1b86c032259b + }; + }; + }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ sensehat_pins: sensehat_pins { ++ brcm,pins = <23>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts new file mode 100644 @@ -45558,62 +42419,116 @@ index 000000000000..ffc872c60648 + <&ssd1351_pins>,"brcm,pins:0"; + }; +}; -diff --git a/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts b/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts +diff --git a/arch/arm/boot/dts/overlays/sunfounder-pipower3-overlay.dts b/arch/arm/boot/dts/overlays/sunfounder-pipower3-overlay.dts new file mode 100644 -index 000000000000..29893d5467d9 +index 000000000000..cd5e8e68f20d --- /dev/null -+++ b/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts -@@ -0,0 +1,51 @@ ++++ b/arch/arm/boot/dts/overlays/sunfounder-pipower3-overlay.dts +@@ -0,0 +1,44 @@ +/dts-v1/; +/plugin/; + +/ { -+ compatible = "brcm,bcm2835"; ++ compatible = "brcm,bcm2835"; + -+ fragment@0 { -+ target = <&i2c1>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ fragment@1 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ fragment@2 { -+ target-path = "/"; -+ __overlay__ { -+ gpio_ir: ir-receiver@c { -+ compatible = "gpio-ir-receiver"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&gpio_ir_pins>; ++ fragment@0 { ++ target-path = "/chosen"; ++ __overlay__ { ++ power: power { ++ hat_current_supply = <5000>; ++ }; ++ }; ++ }; ++ fragment@1 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ power_ctrl: power_ctrl { ++ compatible = "gpio-poweroff"; ++ gpios = <&gpio 26 0>; ++ force; ++ }; ++ }; ++ }; ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ power_ctrl_pins: power_ctrl_pins { ++ brcm,pins = <26>; ++ brcm,function = <1>; // out ++ }; ++ }; ++ }; ++ __overrides__ { ++ poweroff_pin = <&power_ctrl>,"gpios:4", ++ <&power_ctrl_pins>,"brcm,pins:0"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts b/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts +new file mode 100644 +index 000000000000..fad68ef1813f +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sunfounder-pironman5-overlay.dts +@@ -0,0 +1,55 @@ ++/dts-v1/; ++/plugin/; + -+ // pin number, high or low -+ gpios = <&gpio 12 1>; ++/ { ++ compatible = "brcm,bcm2835"; + -+ // parameter for keymap name -+ linux,rc-map-name = "rc-rc6-mce"; ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@1 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ gpio_ir: ir-receiver@d { ++ compatible = "gpio-ir-receiver"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gpio_ir_pins>; + -+ status = "okay"; -+ }; -+ }; -+ }; -+ fragment@3 { -+ target = <&gpio>; -+ __overlay__ { -+ gpio_ir_pins: gpio_ir_pins@c { -+ brcm,pins = <12>; -+ brcm,function = <0>; -+ brcm,pull = <2>; -+ }; -+ }; -+ }; -+ __overrides__ { -+ ir = <&gpio_ir>,"status"; -+ ir_pins = <&gpio_ir>,"gpios:4", <&gpio_ir>,"reg:0", <&gpio_ir_pins>,"brcm,pins:0", <&gpio_ir_pins>,"reg:0"; -+ }; ++ // pin number, high or low ++ gpios = <&gpio 13 1>; ++ ++ // parameter for keymap name ++ linux,rc-map-name = "rc-rc6-mce"; ++ ++ status = "okay"; ++ }; ++ }; ++ }; ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ gpio_ir_pins: gpio_ir_pins@d { ++ brcm,pins = <13>; ++ brcm,function = <0>; ++ brcm,pull = <2>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ ir = <&gpio_ir>,"status"; ++ ir_pins = ++ <&gpio_ir>,"gpios:4", ++ <&gpio_ir>,"reg:0", ++ <&gpio_ir_pins>,"brcm,pins:0", ++ <&gpio_ir_pins>,"reg:0"; ++ }; +}; diff --git a/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts new file mode 100755 @@ -48788,10 +45703,10 @@ index 000000000000..1e10203dfd86 +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts new file mode 100644 -index 000000000000..8b006fcd9e58 +index 000000000000..73c339ada161 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts -@@ -0,0 +1,81 @@ +@@ -0,0 +1,82 @@ +/* + * vc4-kms-dpi-generic-overlay.dts + */ @@ -48854,8 +45769,8 @@ index 000000000000..8b006fcd9e58 + de-invert = <&timing>, "de-active:0=0"; + pixclk-invert = <&timing>, "pixelclk-active:0=0"; + -+ width-mm = <&panel>, "width-mm:0"; -+ height-mm = <&panel>, "height-mm:0"; ++ width-mm = <&panel_generic>, "width-mm:0"; ++ height-mm = <&panel_generic>, "height-mm:0"; + + rgb565 = <&panel_generic>, "bus-format:0=0x1017", + <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_16bit_gpio0>; @@ -48871,6 +45786,7 @@ index 000000000000..8b006fcd9e58 + rgb888 = <&panel_generic>, "bus-format:0=0x100a", + <&dpi_node_generic>, "pinctrl-0:0=",<&dpi_gpio0>; + bus-format = <&panel_generic>, "bus-format:0"; ++ rgb-order = <&dpi_node_generic>, "rgb_order"; + }; +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi b/arch/arm/boot/dts/overlays/vc4-kms-dpi-hyperpixel.dtsi @@ -50033,12 +46949,137 @@ index 000000000000..5dcd0f2243e2 + }; + }; +}; +diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts +new file mode 100644 +index 000000000000..78e8f46c69cc +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts +@@ -0,0 +1,119 @@ ++/* ++ * Device Tree overlay for Waveshare 4.3" 800x480 panel. ++ * It tries to look like a Pi 7" panel, but fails with some of the timing ++ * options. ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include "edt-ft5406.dtsi" ++ ++/ { ++ /* No compatible as it will have come from edt-ft5406.dtsi */ ++ ++ dsi_frag: fragment@0 { ++ target = <&dsi1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ port { ++ dsi_out: endpoint { ++ remote-endpoint = <&panel_dsi_port>; ++ }; ++ }; ++ ++ panel: panel-dsi-generic@0 { ++ // See panel-dsi.yaml binding ++ compatible = "waveshare,4-3-inch-dsi","panel-dsi"; ++ reg = <0>; ++ power-supply = <®_display>; ++ backlight = <®_display>; ++ dsi-color-format = "RGB888"; ++ mode = "MODE_VIDEO"; ++ width-mm = <0>; ++ height-mm = <0>; ++ ++ port { ++ panel_dsi_port: endpoint { ++ data-lanes = <1>; ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; ++ ++ timing: panel-timing { ++ clock-frequency = <27777000>; ++ hactive = <800>; ++ vactive = <480>; ++ hfront-porch = <59>; ++ hsync-len = <2>; ++ hback-porch = <45>; ++ vfront-porch = <7>; ++ vsync-len = <2>; ++ vback-porch = <22>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ reg_bridge: reg_bridge@1 { ++ reg = <1>; ++ compatible = "regulator-fixed"; ++ regulator-name = "bridge_reg"; ++ gpio = <®_display 0 0>; ++ vin-supply = <®_display>; ++ enable-active-high; ++ }; ++ }; ++ }; ++ ++ i2c_frag: fragment@2 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ reg_display: reg_display@45 { ++ compatible = "raspberrypi,7inch-touchscreen-panel-regulator"; ++ reg = <0x45>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@5 { ++ target = <&ft5406>; ++ __overlay__ { ++ vcc-supply = <®_display>; ++ reset-gpio = <®_display 1 1>; ++ }; ++ }; ++ ++ __overrides__ { ++ dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, ++ <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, ++ <®_bridge>, "reg:0=0", ++ <®_bridge>, "regulator-name=bridge_reg_0"; ++ disable_touch = <&ft5406>, "status=disabled"; ++ }; ++}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts new file mode 100644 -index 000000000000..dfc92726d1bc +index 000000000000..3b03ef09cdb9 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts -@@ -0,0 +1,126 @@ +@@ -0,0 +1,133 @@ +/* + * Device Tree overlay for Waveshare DSI Touchscreens + * @@ -50154,6 +47195,13 @@ index 000000000000..dfc92726d1bc + 4_0_inchC = <&panel>, "compatible=waveshare,4inch-panel", + <&touch>, "touchscreen-size-x:0=720", + <&touch>, "touchscreen-size-y:0=720"; ++ 5_0_inch = <&panel>, "compatible=waveshare,5.0inch-panel", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-inverted-y?"; ++ 6_25_inch = <&panel>, "compatible=waveshare,6.25inch-panel", ++ <&touch>, "touchscreen-inverted-x?", ++ <&touch>, "touchscreen-inverted-y?"; ++ 8_8_inch = <&panel>, "compatible=waveshare,8.8inch-panel"; + i2c1 = <&i2c_frag>, "target:0=",<&i2c1>, + <0>, "-3-4+5"; + disable_touch = <&touch>, "status=disabled"; @@ -50535,7 +47583,7 @@ index 000000000000..c1e53e3ed575 +}; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts new file mode 100644 -index 000000000000..3e976b18e2f1 +index 000000000000..94ab6eb1fbaf --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts @@ -0,0 +1,147 @@ @@ -50544,7 +47592,7 @@ index 000000000000..3e976b18e2f1 +#include "cma-overlay.dts" + +&frag0 { -+ size = <((320-4)*1024*1024)>; ++ size = <(64*1024*1024)>; +}; + +/ { @@ -51527,7 +48575,7 @@ index 000000000000..71ce806186de +}; diff --git a/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts new file mode 100644 -index 000000000000..3dd0b384079d +index 000000000000..d896c59f469b --- /dev/null +++ b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts @@ -0,0 +1,82 @@ @@ -51546,7 +48594,7 @@ index 000000000000..3dd0b384079d + }; + + fragment@1 { -+ target-path="/"; ++ target-path = "/"; + __overlay__ { + wm8960_mclk: wm8960_mclk { + compatible = "fixed-clock"; @@ -51562,17 +48610,18 @@ index 000000000000..3dd0b384079d + #size-cells = <0>; + status = "okay"; + -+ wm8960: wm8960 { ++ wm8960: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + #sound-dai-cells = <0>; + AVDD-supply = <&vdd_5v0_reg>; + DVDD-supply = <&vdd_3v3_reg>; ++ clocks = <&wm8960_mclk>; ++ clock-names = "mclk"; + }; + }; + }; + -+ + fragment@3 { + target = <&sound>; + slave_overlay: __overlay__ { @@ -51600,10 +48649,9 @@ index 000000000000..3dd0b384079d + simple-audio-card,cpu { + sound-dai = <&i2s_clk_producer>; + }; ++ + dailink0_slave: simple-audio-card,codec { + sound-dai = <&wm8960>; -+ clocks = <&wm8960_mclk>; -+ clock-names = "mclk"; + }; + }; + }; @@ -51615,10 +48663,10 @@ index 000000000000..3dd0b384079d +}; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig new file mode 100644 -index 000000000000..f54eaec96297 +index 000000000000..f3b3dcb04041 --- /dev/null +++ b/arch/arm/configs/bcm2709_defconfig -@@ -0,0 +1,1585 @@ +@@ -0,0 +1,1601 @@ +CONFIG_LOCALVERSION="-v7" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -51688,7 +48736,6 @@ index 000000000000..f54eaec96297 +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -51716,7 +48763,7 @@ index 000000000000..f54eaec96297 +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -51951,6 +48998,7 @@ index 000000000000..f54eaec96297 +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -52063,11 +49111,14 @@ index 000000000000..f54eaec96297 +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_TI_ST=m @@ -52083,6 +49134,7 @@ index 000000000000..f54eaec96297 +CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -52094,6 +49146,7 @@ index 000000000000..f54eaec96297 +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -52242,7 +49295,7 @@ index 000000000000..f54eaec96297 +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -52309,6 +49362,7 @@ index 000000000000..f54eaec96297 +CONFIG_SPI_BCM2835=m +CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_GPIO=m ++CONFIG_SPI_RP2040_GPIO_BRIDGE=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_PPS_CLIENT_LDISC=m @@ -52548,6 +49602,7 @@ index 000000000000..f54eaec96297 +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX500=m +CONFIG_VIDEO_IMX519=m +CONFIG_VIDEO_IMX708=m +CONFIG_VIDEO_MT9V011=m @@ -52637,6 +49692,7 @@ index 000000000000..f54eaec96297 +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -52752,6 +49808,7 @@ index 000000000000..f54eaec96297 +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -52782,6 +49839,7 @@ index 000000000000..f54eaec96297 +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -52798,6 +49856,7 @@ index 000000000000..f54eaec96297 +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -52809,6 +49868,7 @@ index 000000000000..f54eaec96297 +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -52827,6 +49887,8 @@ index 000000000000..f54eaec96297 +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -53037,6 +50099,7 @@ index 000000000000..f54eaec96297 +CONFIG_MAX31856=m +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m @@ -53097,6 +50160,7 @@ index 000000000000..f54eaec96297 +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -53206,10 +50270,10 @@ index 000000000000..f54eaec96297 +# CONFIG_UPROBE_EVENTS is not set diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig new file mode 100644 -index 000000000000..442e18282bdb +index 000000000000..e747b7b0991c --- /dev/null +++ b/arch/arm/configs/bcm2711_defconfig -@@ -0,0 +1,1615 @@ +@@ -0,0 +1,1633 @@ +CONFIG_LOCALVERSION="-v7l" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -53280,7 +50344,6 @@ index 000000000000..442e18282bdb +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -53307,7 +50370,7 @@ index 000000000000..442e18282bdb +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -53543,6 +50606,7 @@ index 000000000000..442e18282bdb +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -53660,11 +50724,14 @@ index 000000000000..442e18282bdb +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_NVME=y +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m @@ -53683,6 +50750,7 @@ index 000000000000..442e18282bdb +CONFIG_SATA_MV=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -53695,6 +50763,7 @@ index 000000000000..442e18282bdb +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -53851,7 +50920,7 @@ index 000000000000..442e18282bdb +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -53921,6 +50990,7 @@ index 000000000000..442e18282bdb +CONFIG_SPI_BCM2835=m +CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_GPIO=m ++CONFIG_SPI_RP2040_GPIO_BRIDGE=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_PPS_CLIENT_LDISC=m @@ -54135,6 +51205,8 @@ index 000000000000..442e18282bdb +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_MEDIA_PCI_SUPPORT=y ++CONFIG_MEDIA_PCI_HAILO=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m @@ -54161,6 +51233,7 @@ index 000000000000..442e18282bdb +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX500=m +CONFIG_VIDEO_IMX519=m +CONFIG_VIDEO_IMX708=m +CONFIG_VIDEO_MT9V011=m @@ -54251,6 +51324,7 @@ index 000000000000..442e18282bdb +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -54366,6 +51440,7 @@ index 000000000000..442e18282bdb +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -54398,6 +51473,7 @@ index 000000000000..442e18282bdb +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -54414,6 +51490,7 @@ index 000000000000..442e18282bdb +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -54425,6 +51502,7 @@ index 000000000000..442e18282bdb +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -54443,6 +51521,8 @@ index 000000000000..442e18282bdb +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -54655,6 +51735,7 @@ index 000000000000..442e18282bdb +CONFIG_MAX31856=m +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m @@ -54716,6 +51797,7 @@ index 000000000000..442e18282bdb +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -54827,10 +51909,10 @@ index 000000000000..442e18282bdb +# CONFIG_UPROBE_EVENTS is not set diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig new file mode 100644 -index 000000000000..4c2cf05be22b +index 000000000000..a11286624e01 --- /dev/null +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -0,0 +1,1578 @@ +@@ -0,0 +1,1594 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y @@ -54895,7 +51977,6 @@ index 000000000000..4c2cf05be22b +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -54923,7 +52004,7 @@ index 000000000000..4c2cf05be22b +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -55158,6 +52239,7 @@ index 000000000000..4c2cf05be22b +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -55270,11 +52352,14 @@ index 000000000000..4c2cf05be22b +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_TI_ST=m @@ -55290,6 +52375,7 @@ index 000000000000..4c2cf05be22b +CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -55301,6 +52387,7 @@ index 000000000000..4c2cf05be22b +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -55449,7 +52536,7 @@ index 000000000000..4c2cf05be22b +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -55516,6 +52603,7 @@ index 000000000000..4c2cf05be22b +CONFIG_SPI_BCM2835=m +CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_GPIO=m ++CONFIG_SPI_RP2040_GPIO_BRIDGE=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_PPS_CLIENT_LDISC=m @@ -55754,6 +52842,7 @@ index 000000000000..4c2cf05be22b +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX500=m +CONFIG_VIDEO_IMX519=m +CONFIG_VIDEO_IMX708=m +CONFIG_VIDEO_MT9V011=m @@ -55843,6 +52932,7 @@ index 000000000000..4c2cf05be22b +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -55957,6 +53047,7 @@ index 000000000000..4c2cf05be22b +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -55987,6 +53078,7 @@ index 000000000000..4c2cf05be22b +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -56003,6 +53095,7 @@ index 000000000000..4c2cf05be22b +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -56014,6 +53107,7 @@ index 000000000000..4c2cf05be22b +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -56032,6 +53126,8 @@ index 000000000000..4c2cf05be22b +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -56242,6 +53338,7 @@ index 000000000000..4c2cf05be22b +CONFIG_MAX31856=m +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m @@ -56301,6 +53398,7 @@ index 000000000000..4c2cf05be22b +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -56521,10 +53619,10 @@ index 6c607c68f3ad..ba7fc0bc9a15 100644 + #endif diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h -index 2162ebc6c77a..e766a121555a 100644 +index c28f5ec21e41..c59c5e63f2dd 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h -@@ -500,6 +500,9 @@ do { \ +@@ -499,6 +499,9 @@ do { \ extern unsigned long __must_check arm_copy_from_user(void *to, const void __user *from, unsigned long n); @@ -56535,10 +53633,10 @@ index 2162ebc6c77a..e766a121555a 100644 raw_copy_from_user(void *to, const void __user *from, unsigned long n) { diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c -index 9b51562b1f86..d7a1048763a2 100644 +index d2c8e5313539..bb320f08ad2f 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c -@@ -64,6 +64,8 @@ +@@ -57,6 +57,8 @@ static unsigned long dfl_fiq_insn; static struct pt_regs dfl_fiq_regs; @@ -56547,7 +53645,7 @@ index 9b51562b1f86..d7a1048763a2 100644 /* Default reacquire function * - we always relinquish FIQ control * - we always reacquire FIQ control -@@ -148,6 +150,8 @@ static int fiq_start; +@@ -141,6 +143,8 @@ static int fiq_start; void enable_fiq(int fiq) { @@ -56584,10 +53682,10 @@ index 3f0d5c3dae11..cfdbcc9826c0 100644 /* diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c -index 5cfc9c5056a7..0ea30401beaa 100644 +index c66b560562b3..9e312aad369f 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c -@@ -1277,6 +1277,8 @@ static int c_show(struct seq_file *m, void *v) +@@ -1276,6 +1276,8 @@ static int c_show(struct seq_file *m, void *v) { int i, j; u32 cpuid; @@ -56596,7 +53694,7 @@ index 5cfc9c5056a7..0ea30401beaa 100644 for_each_online_cpu(i) { /* -@@ -1336,6 +1338,14 @@ static int c_show(struct seq_file *m, void *v) +@@ -1335,6 +1337,14 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "Revision\t: %04x\n", system_rev); seq_printf(m, "Serial\t\t: %s\n", system_serial); @@ -58108,7 +55206,7 @@ index 2f6163f05e93..f5a5e2e1084a 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig -index 8789d93a7c04..d3206a2a257b 100644 +index 8789d93a7c04..cf6b751c4eaf 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -159,9 +159,11 @@ config ARCH_BCM2835 @@ -58123,27 +55221,10 @@ index 8789d93a7c04..d3206a2a257b 100644 help This enables support for the Broadcom BCM2711 and BCM283x SoCs. This SoC is used in the Raspberry Pi and Roku 2 devices. -@@ -180,6 +182,30 @@ config ARCH_BCM_53573 +@@ -180,6 +182,13 @@ config ARCH_BCM_53573 The base chip is BCM53573 and there are some packaging modifications like BCM47189 and BCM47452. -+config ARCH_BCM_63XX -+ bool "Broadcom BCM63xx DSL SoC" -+ depends on ARCH_MULTI_V7 -+ select ARCH_HAS_RESET_CONTROLLER -+ select ARM_ERRATA_754322 -+ select ARM_ERRATA_764369 if SMP -+ select ARM_GIC -+ select ARM_GLOBAL_TIMER -+ select CACHE_L2X0 -+ select HAVE_ARM_ARCH_TIMER -+ select HAVE_ARM_TWD if SMP -+ select HAVE_ARM_SCU if SMP -+ help -+ This enables support for systems based on Broadcom DSL SoCs. -+ It currently supports the 'BCM63XX' ARM-based family, which includes -+ the BCM63138 variant. -+ +config BCM2835_FAST_MEMCPY + bool "Enable optimized __copy_to_user and __copy_from_user" + depends on ARCH_BCM2835 && ARCH_MULTI_V6 @@ -58467,10 +55548,10 @@ index 7e8773a2d99d..a1ff693e49bf 100644 /* * Save the userland NEON/VFP state. Under UP, diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index fc56e4e30e29..bb49f48de832 100644 +index c11aa218c08e..8e661da1e5af 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig -@@ -124,7 +124,8 @@ config ARM64 +@@ -126,7 +126,8 @@ config ARM64 select CRC32 select DCACHE_WORD_ACCESS select DYNAMIC_FTRACE if FUNCTION_TRACER @@ -58480,6 +55561,23 @@ index fc56e4e30e29..bb49f48de832 100644 select DMA_DIRECT_REMAP select EDAC_SUPPORT select FRAME_POINTER +@@ -1598,6 +1599,16 @@ config ARCH_CUSTOM_NUMA_DISTANCE + + If unsure, say N. + ++config NUMA_EMULATION ++ bool "NUMA emulation" ++ depends on NUMA ++ select GENERIC_ARCH_NUMA_EMULATION ++ help ++ Enable NUMA emulation support. A flat machine will be split into ++ virtual nodes when booted with "numa=fake=N", where N is the number ++ of nodes, the system RAM will be split into N equal chunks, and ++ assigned to each node. ++ + source "kernel/Kconfig.hz" + + config ARCH_SPARSEMEM_ENABLE diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 30dd6347a929..a30874eddeae 100644 --- a/arch/arm64/boot/dts/Makefile @@ -58491,10 +55589,10 @@ index 30dd6347a929..a30874eddeae 100644 + +subdir-y += overlays diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile -index 8b4591ddd27c..6dd8659a7d8a 100644 +index 8b4591ddd27c..5dd4c5c77e2f 100644 --- a/arch/arm64/boot/dts/broadcom/Makefile +++ b/arch/arm64/boot/dts/broadcom/Makefile -@@ -12,6 +12,24 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \ +@@ -12,6 +12,27 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \ bcm2837-rpi-cm3-io3.dtb \ bcm2837-rpi-zero-2-w.dtb @@ -58508,8 +55606,11 @@ index 8b4591ddd27c..6dd8659a7d8a 100644 +dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-cm4s.dtb +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-5-b.dtb +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712d0-rpi-5-b.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-500.dtb +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm5io.dtb +dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5-cm4io.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm5io.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2712-rpi-cm5l-cm4io.dtb + subdir-y += bcmbca subdir-y += northstar2 @@ -58577,52 +55678,4988 @@ index 000000000000..c72d752e7400 +#include "arm/broadcom/bcm2711-rpi-cm4s.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts new file mode 100644 -index 000000000000..1457e696f968 +index 000000000000..a63ee4b678a1 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts -@@ -0,0 +1,2 @@ +@@ -0,0 +1,750 @@ +// SPDX-License-Identifier: GPL-2.0 -+#include "arm/broadcom/bcm2712-rpi-5-b.dts" ++/dts-v1/; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define i2c0 _i2c0 ++#define i2c3 _i2c3 ++#define i2c4 _i2c4 ++#define i2c5 _i2c5 ++#define i2c6 _i2c6 ++#define i2c8 _i2c8 ++#define i2s _i2s ++#define pwm0 _pwm0 ++#define pwm1 _pwm1 ++#define spi0 _spi0 ++#define spi3 _spi3 ++#define spi4 _spi4 ++#define spi5 _spi5 ++#define spi6 _spi6 ++#define uart0 _uart0 ++#define uart2 _uart2 ++#define uart5 _uart5 ++ ++#include "bcm2712.dtsi" ++ ++#undef i2c0 ++#undef i2c3 ++#undef i2c4 ++#undef i2c5 ++#undef i2c6 ++#undef i2c8 ++#undef i2s ++#undef pwm0 ++#undef pwm1 ++#undef spi0 ++#undef spi3 ++#undef spi4 ++#undef spi5 ++#undef spi6 ++#undef uart0 ++#undef uart2 ++#undef uart3 ++#undef uart4 ++#undef uart5 ++ ++/ { ++ compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; ++ model = "Raspberry Pi 5"; ++ ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0x28000000>; ++ }; ++ ++ leds: leds { ++ compatible = "gpio-leds"; ++ ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "none"; ++ }; ++ ++ led_act: led-act { ++ label = "ACT"; ++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++ }; ++ }; ++ ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; ++ }; ++ ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ }; ++ ++ wl_on_reg: wl_on_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "wl-on-regulator"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ pinctrl-0 = <&wl_on_pins>; ++ pinctrl-names = "default"; ++ ++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; ++ ++ startup-delay-us = <150000>; ++ enable-active-high; ++ }; ++ ++ clocks: clocks { ++ }; ++ ++ cam1_clk: cam1_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_clk: cam0_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_reg: cam0_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam0_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to MIPI 0 connector ++ }; ++ ++ cam1_reg: cam1_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam1_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 46 0>; // CD1_IO0_MICCLK, to MIPI 1 connector ++ }; ++ ++ cam_dummy_reg: cam_dummy_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam-dummy-reg"; ++ status = "okay"; ++ }; ++ ++ dummy: dummy { ++ // A target for unwanted overlay fragments ++ }; ++ ++ ++ // A few extra labels to keep overlays happy ++ ++ i2c0if: i2c0if {}; ++ i2c0mux: i2c0mux {}; ++}; ++ ++rp1_target: &pcie2 { ++ brcm,enable-mps-rcb; ++ brcm,vdm-qos-map = <0xbbaa9888>; ++ aspm-no-l0s; ++ status = "okay"; ++}; ++ ++&pcie1 { ++ brcm,vdm-qos-map = <0x33333333>; ++}; ++ ++// Add some labels to 2712 device ++ ++// The system UART ++uart10: &_uart0 { status = "okay"; }; ++ ++// The system SPI for the bootloader EEPROM ++spi10: &_spi0 { status = "okay"; }; ++ ++i2c_rp1boot: &_i2c3 { }; ++ ++#include "rp1.dtsi" ++ ++&rp1 { ++ // PCIe address space layout: ++ // 00_00000000-00_00xxxxxx = RP1 peripherals ++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM ++ ++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx ++ // This is the RP1 peripheral space ++ ranges = <0xc0 0x40000000 ++ 0x02000000 0x00 0x00000000 ++ 0x00 0x00400000>; ++ ++ dma-ranges = ++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x10 0x00000000 ++ 0x43000000 0x10 0x00000000 ++ 0x10 0x00000000>, ++ ++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx ++ // This allows the RP1 DMA controller to address RP1 hardware ++ <0xc0 0x40000000 ++ 0x02000000 0x0 0x00000000 ++ 0x0 0x00400000>, ++ ++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x00 0x00000000 ++ 0x02000000 0x10 0x00000000 ++ 0x10 0x00000000>; ++}; ++ ++// Expose RP1 nodes as system nodes with labels ++ ++&rp1_dma { ++ status = "okay"; ++}; ++ ++&rp1_eth { ++ status = "okay"; ++ phy-handle = <&phy1>; ++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; ++ phy-reset-duration = <5>; ++ ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ brcm,powerdown-enable; ++ }; ++}; ++ ++gpio: &rp1_gpio { ++ status = "okay"; ++}; ++ ++aux: &dummy {}; ++ ++&rp1_usb0 { ++ pinctrl-0 = <&usb_vbus_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&rp1_usb1 { ++ status = "okay"; ++}; ++ ++#include "bcm2712-rpi.dtsi" ++ ++i2c_csi_dsi0: &i2c6 { // Note: This is for MIPI0 connector only ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-6"; ++}; ++ ++i2c_csi_dsi1: &i2c4 { // Note: This is for MIPI1 connector only ++ pinctrl-0 = <&rp1_i2c4_40_41>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-4"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility ++ ++csi0: &rp1_csi0 { }; ++csi1: &rp1_csi1 { }; ++dsi0: &rp1_dsi0 { }; ++dsi1: &rp1_dsi1 { }; ++dpi: &rp1_dpi { }; ++vec: &rp1_vec { }; ++dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; ++dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; ++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; ++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; ++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; ++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; ++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; ++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; ++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; ++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; ++ ++/* Add the IOMMUs for some RP1 bus masters */ ++ ++&csi0 { ++ iommus = <&iommu5>; ++}; ++ ++&csi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi0 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dpi { ++ iommus = <&iommu5>; ++}; ++ ++&vec { ++ iommus = <&iommu5>; ++}; ++ ++&ddc0 { ++ status = "disabled"; ++}; ++ ++&ddc1 { ++ status = "disabled"; ++}; ++ ++&hdmi0 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hdmi1 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hvs { ++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; ++ clock-names = "core", "disp"; ++}; ++ ++&mop { ++ status = "disabled"; ++}; ++ ++&moplet { ++ status = "disabled"; ++}; ++ ++&pixelvalve0 { ++ status = "disabled"; ++}; ++ ++&pixelvalve1 { ++ status = "disabled"; ++}; ++ ++&disp_intr { ++ status = "disabled"; ++}; ++ ++/* SDIO1 is used to drive the SD card */ ++&sdio1 { ++ pinctrl-0 = <&emmc_sd_pulls>, <&emmc_aon_cd_pins>; ++ pinctrl-names = "default"; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; ++ bus-width = <4>; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ supports-cqe; ++ cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>; ++ //no-1-8-v; ++ status = "okay"; ++}; ++ ++&pinctrl_aon { ++ emmc_aon_cd_pins: emmc_aon_cd_pins { ++ function = "sd_card_g"; ++ pins = "aon_gpio5"; ++ bias-pull-up; ++ }; ++ ++ /* Slight hack - only one PWM pin (status LED) is usable */ ++ aon_pwm_1pin: aon_pwm_1pin { ++ function = "aon_pwm"; ++ pins = "aon_gpio9"; ++ }; ++}; ++ ++&pinctrl { ++ pwr_button_pins: pwr_button_pins { ++ function = "gpio"; ++ pins = "gpio20"; ++ bias-pull-up; ++ }; ++ ++ wl_on_pins: wl_on_pins { ++ function = "gpio"; ++ pins = "gpio28"; ++ }; ++ ++ bt_shutdown_pins: bt_shutdown_pins { ++ function = "gpio"; ++ pins = "gpio29"; ++ }; ++ ++ emmc_sd_pulls: emmc_sd_pulls { ++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3"; ++ bias-pull-up; ++ }; ++}; ++ ++/* uarta communicates with the BT module */ ++&uarta { ++ uart-has-rtscts; ++ auto-flow-control; ++ status = "okay"; ++ clock-frequency = <96000000>; ++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; ++ local-bd-address = [ 00 00 00 00 00 00 ]; ++ }; ++}; ++ ++&i2c_rp1boot { ++ clock-frequency = <400000>; ++ pinctrl-0 = <&i2c3_m4_agpio0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/ { ++ fan: cooling_fan { ++ status = "disabled"; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ cooling-levels = <0 75 125 175 250>; ++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; ++ rpm-regmap = <&rp1_pwm1>; ++ rpm-offset = <0x3c>; ++ }; ++ ++ pwr_button { ++ compatible = "gpio-keys"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_button_pins>; ++ status = "okay"; ++ ++ pwr_key: pwr { ++ label = "pwr_button"; ++ // linux,code = <205>; // KEY_SUSPEND ++ linux,code = <116>; // KEY_POWER ++ gpios = <&gio 20 GPIO_ACTIVE_LOW>; ++ debounce-interval = <50>; // ms ++ }; ++ }; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++/* SDIO2 drives the WLAN interface */ ++&sdio2 { ++ pinctrl-0 = <&sdio2_30_pins>; ++ pinctrl-names = "default"; ++ bus-width = <4>; ++ vmmc-supply = <&wl_on_reg>; ++ sd-uhs-ddr50; ++ non-removable; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wifi: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++}; ++ ++&rpivid { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ spi10_gpio2: spi10_gpio2 { ++ function = "vc_spi0"; ++ pins = "gpio2", "gpio3", "gpio4"; ++ bias-disable; ++ }; ++ ++ spi10_cs_gpio1: spi10_cs_gpio1 { ++ function = "gpio"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++}; ++ ++spi10_pins: &spi10_gpio2 {}; ++spi10_cs_pins: &spi10_cs_gpio1 {}; ++ ++&spi10 { ++ pinctrl-names = "default"; ++ cs-gpios = <&gio 1 1>; ++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; ++ ++ spidev10: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <20000000>; ++ status = "okay"; ++ }; ++}; ++ ++// ============================================= ++// Board specific stuff here ++ ++&gio_aon { ++ // Don't use GIO_AON as an interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ /delete-property/ interrupt-controller; ++}; ++ ++&main_aon_irq { ++ // Don't use the MAIN_AON_IRQ interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ status = "disabled"; ++}; ++ ++&rp1_pwm1 { ++ status = "disabled"; ++ pinctrl-0 = <&rp1_pwm1_gpio45>; ++ pinctrl-names = "default"; ++}; ++ ++&thermal_trips { ++ cpu_tepid: cpu-tepid { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_warm: cpu-warm { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu-hot { ++ temperature = <67500>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_vhot: cpu-vhot { ++ temperature = <75000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++}; ++ ++&cooling_maps { ++ tepid { ++ trip = <&cpu_tepid>; ++ cooling-device = <&fan 1 1>; ++ }; ++ ++ warm { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan 2 2>; ++ }; ++ ++ hot { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 3 3>; ++ }; ++ ++ vhot { ++ trip = <&cpu_vhot>; ++ cooling-device = <&fan 4 4>; ++ }; ++ ++ melt { ++ trip = <&cpu_crit>; ++ cooling-device = <&fan 4 4>; ++ }; ++}; ++ ++&gio { ++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank ++ // to reduce the clutter in gpioinfo/pinctrl ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "-", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "-", // GPIO_005 ++ "-", // GPIO_006 ++ "-", // GPIO_007 ++ "-", // GPIO_008 ++ "-", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "PCIE_SDA", // GPIO_014 ++ "PCIE_SCL", // GPIO_015 ++ "-", // GPIO_016 ++ "-", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "-", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "-", // AON_GPIO_10 ++ "-", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "-", // AON_GPIO_15 ++ "-", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++ ++ rp1_run_hog { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RP1 RUN pin"; ++ }; ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_RP1_WAKE", // GPIO28 ++ "FAN_TACH", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "-", // GPIO33 ++ ++ "CD0_IO0_MICCLK", // GPIO34 ++ "CD0_IO0_MICDAT0", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "-", // GPIO37 ++ "CD0_SDA", // GPIO38 ++ "CD0_SCL", // GPIO39 ++ "CD1_SDA", // GPIO40 ++ "CD1_SCL", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "FAN_PWM", // GPIO45 ++ "CD1_IO0_MICCLK", // GPIO46 ++ "2712_WAKE", // GPIO47 ++ "CD1_IO1_MICDAT1", // GPIO48 ++ "EN_MAX_USB_CUR", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++ ++ usb_vbus_pins: usb_vbus_pins { ++ function = "vbus1"; ++ pins = "gpio42", "gpio43"; ++ }; ++}; ++ ++/ { ++ __overrides__ { ++ sd_cqe = <&sdio1>, "supports-cqe?"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts +new file mode 100644 +index 000000000000..1862e55fa1d2 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts +@@ -0,0 +1,142 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm2712d0-rpi-5-b.dts" ++ ++/ { ++ compatible = "raspberrypi,500", "brcm,bcm2712"; ++ model = "Raspberry Pi 500"; ++}; ++ ++&pwr_key { ++ debounce-interval = <400>; ++}; ++ ++&gio { ++ gpio-line-names = ++ "", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "", // GPIO_005 ++ "", // GPIO_006 ++ "", // GPIO_007 ++ "", // GPIO_008 ++ "", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "M2_DET_WAKE", // GPIO_014 ++ "M2_PWR_EN", // GPIO_015 ++ "", // GPIO_016 ++ "", // GPIO_017 ++ "KEYB_BOOTSEL", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "KEYB_RUN", // GPIO_021 ++ "-", // GPIO_022 ++ "USER_LED", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "", // AON_GPIO_10 ++ "", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "", // AON_GPIO_15 ++ "", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_RP1_WAKE", // GPIO28 ++ "-", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "PCIE_DET_WAKE", // GPIO33 ++ ++ "-", // GPIO34 ++ "-", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "-", // GPIO37 ++ "-", // GPIO38 ++ "-", // GPIO39 ++ "CD1_SDA", // GPIO40 ++ "CD1_SCL", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "-", // GPIO45 ++ "-", // GPIO46 ++ "HOST_WAKE", // GPIO47 ++ "-", // GPIO48 ++ "EN_MAX_USB_CUR", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++}; +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi +new file mode 100644 +index 000000000000..1b4c42a61817 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++i2c_csi_dsi0: &i2c0 { // Note: For CAM0 and DISP0 connectors ++}; ++ ++i2c_csi_dsi1: &i2c6 { // Note: For CAM1, DISP1, on-board RTC, and fan controller ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-6"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi1 { }; // The connector that needs no jumper to enable ++ ++&aliases { ++ /delete-property/ i2c11; ++ i2c10 = &i2c_csi_dsi; ++}; ++ ++// The RP1 USB3 interfaces are not usable on CM4IO ++ ++&rp1_usb0 { ++ status = "disabled"; ++}; ++ ++&rp1_usb1 { ++ status = "disabled"; ++}; diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts new file mode 100644 -index 000000000000..3815e40cc0aa +index 000000000000..96cd7cf735d5 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts -@@ -0,0 +1,2 @@ +@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 -+#include "arm/broadcom/bcm2712-rpi-cm5-cm4io.dts" ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++#include "bcm2712-rpi-cm4io.dtsi" diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts new file mode 100644 -index 000000000000..e2215a3f6276 +index 000000000000..6b5e147d569d --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts -@@ -0,0 +1,2 @@ +@@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 -+#include "arm/broadcom/bcm2712-rpi-cm5-cm5io.dts" ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++#include "bcm2712-rpi-cm5io.dtsi" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +new file mode 100644 +index 000000000000..1a293249ac43 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -0,0 +1,754 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define i2c0 _i2c0 ++#define i2c3 _i2c3 ++#define i2c4 _i2c4 ++#define i2c5 _i2c5 ++#define i2c6 _i2c6 ++#define i2c8 _i2c8 ++#define i2s _i2s ++#define pwm0 _pwm0 ++#define pwm1 _pwm1 ++#define spi0 _spi0 ++#define spi3 _spi3 ++#define spi4 _spi4 ++#define spi5 _spi5 ++#define spi6 _spi6 ++#define uart0 _uart0 ++#define uart2 _uart2 ++#define uart5 _uart5 ++ ++#include "bcm2712.dtsi" ++ ++#undef i2c0 ++#undef i2c3 ++#undef i2c4 ++#undef i2c5 ++#undef i2c6 ++#undef i2c8 ++#undef i2s ++#undef pwm0 ++#undef pwm1 ++#undef spi0 ++#undef spi3 ++#undef spi4 ++#undef spi5 ++#undef spi6 ++#undef uart0 ++#undef uart2 ++#undef uart3 ++#undef uart4 ++#undef uart5 ++ ++/ { ++ compatible = "raspberrypi,5-compute-module", "brcm,bcm2712"; ++ model = "Raspberry Pi Compute Module 5"; ++ ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0x28000000>; ++ }; ++ ++ leds: leds { ++ compatible = "gpio-leds"; ++ ++ led_pwr: led-pwr { ++ label = "PWR"; ++ gpios = <&rp1_gpio 44 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "none"; ++ }; ++ ++ led_act: led-act { ++ label = "ACT"; ++ gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ linux,default-trigger = "mmc0"; ++ }; ++ }; ++ ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpios = <&gio_aon 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ }; ++ ++ wl_on_reg: wl_on_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "wl-on-regulator"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ pinctrl-0 = <&wl_on_pins>; ++ pinctrl-names = "default"; ++ ++ gpio = <&gio 28 GPIO_ACTIVE_HIGH>; ++ ++ startup-delay-us = <150000>; ++ enable-active-high; ++ }; ++ ++ clocks: clocks { ++ }; ++ ++ cam1_clk: cam1_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_clk: cam0_clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ cam0_reg: cam0_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam0_reg"; ++ enable-active-high; ++ status = "okay"; ++ gpio = <&rp1_gpio 34 0>; // CD0_IO0_MICCLK, to CAM_GPIO on connector ++ }; ++ ++ cam_dummy_reg: cam_dummy_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "cam-dummy-reg"; ++ status = "okay"; ++ }; ++ ++ dummy: dummy { ++ // A target for unwanted overlay fragments ++ }; ++ ++ ++ // A few extra labels to keep overlays happy ++ ++ i2c0if: i2c0if {}; ++ i2c0mux: i2c0mux {}; ++}; ++ ++rp1_target: &pcie2 { ++ brcm,enable-mps-rcb; ++ brcm,vdm-qos-map = <0xbbaa9888>; ++ aspm-no-l0s; ++ status = "okay"; ++}; ++ ++// Add some labels to 2712 device ++ ++// The system UART ++uart10: &_uart0 { status = "okay"; }; ++ ++// The system SPI for the bootloader EEPROM ++spi10: &_spi0 { status = "okay"; }; ++ ++i2c_rp1boot: &_i2c3 { }; ++ ++#include "rp1.dtsi" ++ ++&rp1 { ++ // PCIe address space layout: ++ // 00_00000000-00_00xxxxxx = RP1 peripherals ++ // 10_00000000-1x_xxxxxxxx = up to 64GB system RAM ++ ++ // outbound access aimed at PCIe 0_00xxxxxx -> RP1 c0_40xxxxxx ++ // This is the RP1 peripheral space ++ ranges = <0xc0 0x40000000 ++ 0x02000000 0x00 0x00000000 ++ 0x00 0x00400000>; ++ ++ dma-ranges = ++ // inbound RP1 1x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x10 0x00000000 ++ 0x43000000 0x10 0x00000000 ++ 0x10 0x00000000>, ++ ++ // inbound RP1 c0_40xxxxxx -> PCIe 00_00xxxxxx ++ // This allows the RP1 DMA controller to address RP1 hardware ++ <0xc0 0x40000000 ++ 0x02000000 0x0 0x00000000 ++ 0x0 0x00400000>, ++ ++ // inbound RP1 0x_xxxxxxxx -> PCIe 1x_xxxxxxxx ++ <0x00 0x00000000 ++ 0x02000000 0x10 0x00000000 ++ 0x10 0x00000000>; ++}; ++ ++// Expose RP1 nodes as system nodes with labels ++ ++&rp1_dma { ++ status = "okay"; ++}; ++ ++&rp1_eth { ++ status = "okay"; ++ phy-handle = <&phy1>; ++ phy-reset-gpios = <&rp1_gpio 32 GPIO_ACTIVE_LOW>; ++ phy-reset-duration = <5>; ++ ++ phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ brcm,powerdown-enable; ++ interrupt-parent = <&gpio>; ++ interrupts = <37 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; ++ ++gpio: &rp1_gpio { ++ status = "okay"; ++}; ++ ++aux: &dummy {}; ++ ++&rp1_usb0 { ++ pinctrl-0 = <&usb_vbus_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&rp1_usb1 { ++ status = "okay"; ++}; ++ ++#include "bcm2712-rpi.dtsi" ++ ++cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg ++}; ++ ++csi0: &rp1_csi0 { }; ++csi1: &rp1_csi1 { }; ++dsi0: &rp1_dsi0 { }; ++dsi1: &rp1_dsi1 { }; ++dpi: &rp1_dpi { }; ++vec: &rp1_vec { }; ++dpi_gpio0: &rp1_dpi_24bit_gpio0 { }; ++dpi_gpio1: &rp1_dpi_24bit_gpio2 { }; ++dpi_18bit_cpadhi_gpio0: &rp1_dpi_18bit_cpadhi_gpio0 { }; ++dpi_18bit_cpadhi_gpio2: &rp1_dpi_18bit_cpadhi_gpio2 { }; ++dpi_18bit_gpio0: &rp1_dpi_18bit_gpio0 { }; ++dpi_18bit_gpio2: &rp1_dpi_18bit_gpio2 { }; ++dpi_16bit_cpadhi_gpio0: &rp1_dpi_16bit_cpadhi_gpio0 { }; ++dpi_16bit_cpadhi_gpio2: &rp1_dpi_16bit_cpadhi_gpio2 { }; ++dpi_16bit_gpio0: &rp1_dpi_16bit_gpio0 { }; ++dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; ++ ++/* Add the IOMMUs for some RP1 bus masters */ ++ ++&csi0 { ++ iommus = <&iommu5>; ++}; ++ ++&csi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi0 { ++ iommus = <&iommu5>; ++}; ++ ++&dsi1 { ++ iommus = <&iommu5>; ++}; ++ ++&dpi { ++ iommus = <&iommu5>; ++}; ++ ++&vec { ++ iommus = <&iommu5>; ++}; ++ ++&ddc0 { ++ status = "disabled"; ++}; ++ ++&ddc1 { ++ status = "disabled"; ++}; ++ ++&hdmi0 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hdmi1 { ++ clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; ++ clock-names = "hdmi", "bvb", "audio", "cec"; ++ status = "disabled"; ++}; ++ ++&hvs { ++ clocks = <&firmware_clocks 4>, <&firmware_clocks 16>; ++ clock-names = "core", "disp"; ++}; ++ ++&mop { ++ status = "disabled"; ++}; ++ ++&moplet { ++ status = "disabled"; ++}; ++ ++&pixelvalve0 { ++ status = "disabled"; ++}; ++ ++&pixelvalve1 { ++ status = "disabled"; ++}; ++ ++&disp_intr { ++ status = "disabled"; ++}; ++ ++/* SDIO1 is used to drive the eMMC/SD card */ ++&sdio1 { ++ pinctrl-0 = <&emmc_cmddat_pulls>, <&emmc_ds_pull>; ++ pinctrl-names = "default"; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; ++ bus-width = <8>; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ mmc-hs200-1_8v; ++ mmc-hs400-1_8v; ++ mmc-hs400-enhanced-strobe; ++ broken-cd; ++ supports-cqe; ++ status = "okay"; ++}; ++ ++&pinctrl_aon { ++ ant_pins: ant_pins { ++ function = "gpio"; ++ pins = "aon_gpio5", "aon_gpio6"; ++ }; ++ ++ /* Slight hack - only one PWM pin (status LED) is usable */ ++ aon_pwm_1pin: aon_pwm_1pin { ++ function = "aon_pwm"; ++ pins = "aon_gpio9"; ++ }; ++}; ++ ++&pinctrl { ++ pwr_button_pins: pwr_button_pins { ++ function = "gpio"; ++ pins = "gpio20"; ++ bias-pull-up; ++ }; ++ ++ wl_on_pins: wl_on_pins { ++ function = "gpio"; ++ pins = "gpio28"; ++ }; ++ ++ bt_shutdown_pins: bt_shutdown_pins { ++ function = "gpio"; ++ pins = "gpio29"; ++ }; ++ ++ emmc_ds_pull: emmc_ds_pull { ++ pins = "emmc_ds"; ++ bias-pull-down; ++ }; ++ ++ emmc_cmddat_pulls: emmc_cmddat_pulls { ++ pins = "emmc_cmd", "emmc_dat0", "emmc_dat1", "emmc_dat2", "emmc_dat3", ++ "emmc_dat4", "emmc_dat5", "emmc_dat6", "emmc_dat7"; ++ bias-pull-up; ++ }; ++}; ++ ++/* uarta communicates with the BT module */ ++&uarta { ++ uart-has-rtscts; ++ auto-flow-control; ++ status = "okay"; ++ clock-frequency = <96000000>; ++ pinctrl-0 = <&uarta_24_pins &bt_shutdown_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth: bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <3000000>; ++ shutdown-gpios = <&gio 29 GPIO_ACTIVE_HIGH>; ++ local-bd-address = [ 00 00 00 00 00 00 ]; ++ }; ++}; ++ ++&i2c_rp1boot { ++ clock-frequency = <400000>; ++ pinctrl-0 = <&i2c3_m4_agpio0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/ { ++ fan: cooling_fan { ++ status = "disabled"; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ cooling-levels = <0 75 125 175 250>; ++ pwms = <&rp1_pwm1 3 41566 PWM_POLARITY_INVERTED>; ++ rpm-regmap = <&rp1_pwm1>; ++ rpm-offset = <0x3c>; ++ }; ++ ++ pwr_button { ++ compatible = "gpio-keys"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_button_pins>; ++ status = "okay"; ++ ++ pwr_key: pwr { ++ label = "pwr_button"; ++ // linux,code = <205>; // KEY_SUSPEND ++ linux,code = <116>; // KEY_POWER ++ gpios = <&gio 20 GPIO_ACTIVE_LOW>; ++ debounce-interval = <50>; // ms ++ }; ++ }; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++/* SDIO2 drives the WLAN interface */ ++&sdio2 { ++ pinctrl-0 = <&sdio2_30_pins>, <&ant_pins>; ++ pinctrl-names = "default"; ++ bus-width = <4>; ++ vmmc-supply = <&wl_on_reg>; ++ sd-uhs-ddr50; ++ non-removable; ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ wifi: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++}; ++ ++&rpivid { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ spi10_gpio2: spi10_gpio2 { ++ function = "vc_spi0"; ++ pins = "gpio2", "gpio3", "gpio4"; ++ bias-disable; ++ }; ++ ++ spi10_cs_gpio1: spi10_cs_gpio1 { ++ function = "gpio"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++}; ++ ++spi10_pins: &spi10_gpio2 {}; ++spi10_cs_pins: &spi10_cs_gpio1 {}; ++ ++&spi10 { ++ pinctrl-names = "default"; ++ cs-gpios = <&gio 1 1>; ++ pinctrl-0 = <&spi10_pins &spi10_cs_pins>; ++ ++ spidev10: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <20000000>; ++ status = "okay"; ++ }; ++}; ++ ++// ============================================= ++// Board specific stuff here ++ ++&gio_aon { ++ // Don't use GIO_AON as an interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ /delete-property/ interrupt-controller; ++}; ++ ++&main_aon_irq { ++ // Don't use the MAIN_AON_IRQ interrupt controller because it will ++ // clash with the firmware monitoring the PMIC interrupt via the VPU. ++ ++ status = "disabled"; ++}; ++ ++&rp1_pwm1 { ++ status = "disabled"; ++ pinctrl-0 = <&rp1_pwm1_gpio45>; ++ pinctrl-names = "default"; ++}; ++ ++&thermal_trips { ++ cpu_tepid: cpu-tepid { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_warm: cpu-warm { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu-hot { ++ temperature = <67500>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ cpu_vhot: cpu-vhot { ++ temperature = <75000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++}; ++ ++&cooling_maps { ++ tepid { ++ trip = <&cpu_tepid>; ++ cooling-device = <&fan 1 1>; ++ }; ++ ++ warm { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan 2 2>; ++ }; ++ ++ hot { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 3 3>; ++ }; ++ ++ vhot { ++ trip = <&cpu_vhot>; ++ cooling-device = <&fan 4 4>; ++ }; ++ ++ melt { ++ trip = <&cpu_crit>; ++ cooling-device = <&fan 4 4>; ++ }; ++}; ++ ++&gio { ++ // The GPIOs above 35 are not used on Pi 5, so shrink the upper bank ++ // to reduce the clutter in gpioinfo/pinctrl ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "-", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "-", // GPIO_005 ++ "-", // GPIO_006 ++ "-", // GPIO_007 ++ "-", // GPIO_008 ++ "-", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "-", // GPIO_014 ++ "-", // GPIO_015 ++ "-", // GPIO_016 ++ "-", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "ANT1", // AON_GPIO_05 ++ "ANT2", // AON_GPIO_06 ++ "-", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "-", // AON_GPIO_10 ++ "-", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "-", // AON_GPIO_15 ++ "-", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++ ++ rp1_run_hog { ++ gpio-hog; ++ gpios = <2 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RP1 RUN pin"; ++ }; ++ ++ ant1: ant1-hog { ++ gpio-hog; ++ gpios = <5 GPIO_ACTIVE_HIGH>; ++ /* internal antenna enabled */ ++ output-high; ++ line-name = "ant1"; ++ }; ++ ++ ant2: ant2-hog { ++ gpio-hog; ++ gpios = <6 GPIO_ACTIVE_HIGH>; ++ /* external antenna disabled */ ++ output-low; ++ line-name = "ant2"; ++ }; ++}; ++ ++&rp1_gpio { ++ gpio-line-names = ++ "ID_SDA", // GPIO0 ++ "ID_SCL", // GPIO1 ++ "GPIO2", // GPIO2 ++ "GPIO3", // GPIO3 ++ "GPIO4", // GPIO4 ++ "GPIO5", // GPIO5 ++ "GPIO6", // GPIO6 ++ "GPIO7", // GPIO7 ++ "GPIO8", // GPIO8 ++ "GPIO9", // GPIO9 ++ "GPIO10", // GPIO10 ++ "GPIO11", // GPIO11 ++ "GPIO12", // GPIO12 ++ "GPIO13", // GPIO13 ++ "GPIO14", // GPIO14 ++ "GPIO15", // GPIO15 ++ "GPIO16", // GPIO16 ++ "GPIO17", // GPIO17 ++ "GPIO18", // GPIO18 ++ "GPIO19", // GPIO19 ++ "GPIO20", // GPIO20 ++ "GPIO21", // GPIO21 ++ "GPIO22", // GPIO22 ++ "GPIO23", // GPIO23 ++ "GPIO24", // GPIO24 ++ "GPIO25", // GPIO25 ++ "GPIO26", // GPIO26 ++ "GPIO27", // GPIO27 ++ ++ "PCIE_PWR_EN", // GPIO28 ++ "FAN_TACH", // GPIO29 ++ "HOST_SDA", // GPIO30 ++ "HOST_SCL", // GPIO31 ++ "ETH_RST_N", // GPIO32 ++ "PCIE_DET_WAKE", // GPIO33 ++ ++ "CD0_IO0_MICCLK", // GPIO34 ++ "CD0_IO0_MICDAT0", // GPIO35 ++ "RP1_PCIE_CLKREQ_N", // GPIO36 ++ "ETH_IRQ_N", // GPIO37 ++ "SDA0", // GPIO38 ++ "SCL0", // GPIO39 ++ "-", // GPIO40 ++ "-", // GPIO41 ++ "USB_VBUS_EN", // GPIO42 ++ "USB_OC_N", // GPIO43 ++ "RP1_STAT_LED", // GPIO44 ++ "FAN_PWM", // GPIO45 ++ "-", // GPIO46 ++ "2712_WAKE", // GPIO47 ++ "-", // GPIO48 ++ "-", // GPIO49 ++ "-", // GPIO50 ++ "-", // GPIO51 ++ "-", // GPIO52 ++ "-"; // GPIO53 ++ ++ usb_vbus_pins: usb_vbus_pins { ++ function = "vbus1"; ++ pins = "gpio42", "gpio43"; ++ }; ++}; ++ ++/ { ++ __overrides__ { ++ ant1 = <&ant1>,"output-high?=on", ++ <&ant1>, "output-low?=off", ++ <&ant2>, "output-high?=off", ++ <&ant2>, "output-low?=on"; ++ ant2 = <&ant1>,"output-high?=off", ++ <&ant1>, "output-low?=on", ++ <&ant2>, "output-high?=on", ++ <&ant2>, "output-low?=off"; ++ noant = <&ant1>,"output-high?=off", ++ <&ant1>, "output-low?=on", ++ <&ant2>, "output-high?=off", ++ <&ant2>, "output-low?=on"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi +new file mode 100644 +index 000000000000..788fda2fcbfb +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi +@@ -0,0 +1,14 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++i2c_csi_dsi1: &i2c0 { // Note: This is for CAM/DISP 1 connector ++ symlink = "i2c-11"; ++}; ++ ++i2c_csi_dsi0: &i2c6 { // Note: This is for CAM/DISP 0 connector ++ pinctrl-0 = <&rp1_i2c6_38_39>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++ symlink = "i2c-6"; ++}; ++ ++i2c_csi_dsi: &i2c_csi_dsi0 { }; // The connector that needs no jumper to enable +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts +new file mode 100644 +index 000000000000..71259a673d99 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts +@@ -0,0 +1,5 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5l.dtsi" ++#include "bcm2712-rpi-cm4io.dtsi" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts +new file mode 100644 +index 000000000000..11a56dfb7b48 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts +@@ -0,0 +1,5 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5l.dtsi" ++#include "bcm2712-rpi-cm5io.dtsi" +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi +new file mode 100644 +index 000000000000..98ac6c113e81 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi +@@ -0,0 +1,22 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++ ++#include "bcm2712-rpi-cm5.dtsi" ++ ++/ { ++ model = "Raspberry Pi Compute Module 5 Lite"; ++}; ++ ++&sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-max-microvolt = <3300000>; ++ regulator-settling-time-us = <5000>; ++ gpios = <&gio_aon 3 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++}; ++ ++&sdio1 { ++ /delete-property/ mmc-hs400-1_8v; ++ /delete-property/ mmc-hs400-enhanced-strobe; ++}; +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +new file mode 100644 +index 000000000000..25e37b99b054 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +@@ -0,0 +1,466 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++ ++&soc { ++ firmware: firmware { ++ compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ mboxes = <&mailbox>; ++ dma-ranges; ++ ++ firmware_clocks: clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ #clock-cells = <1>; ++ }; ++ ++ reset: reset { ++ compatible = "raspberrypi,firmware-reset"; ++ #reset-cells = <1>; ++ }; ++ ++ vcio: vcio { ++ compatible = "raspberrypi,vcio"; ++ }; ++ }; ++ ++ power: power { ++ compatible = "raspberrypi,bcm2835-power"; ++ firmware = <&firmware>; ++ #power-domain-cells = <1>; ++ }; ++ ++ fb: fb { ++ compatible = "brcm,bcm2708-fb"; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; ++ ++ rpi_rtc: rpi_rtc { ++ compatible = "raspberrypi,rpi-rtc"; ++ firmware = <&firmware>; ++ status = "okay"; ++ trickle-charge-microvolt = <0>; ++ }; ++ ++ nvmem { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ nvmem_otp: nvmem_otp { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <0 192>; ++ status = "okay"; ++ }; ++ ++ nvmem_cust: nvmem_cust { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <1 8>; ++ status = "okay"; ++ }; ++ ++ nvmem_mac: nvmem_mac { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <2 6>; ++ status = "okay"; ++ }; ++ ++ nvmem_priv: nvmem_priv { ++ compatible = "raspberrypi,rpi-otp"; ++ firmware = <&firmware>; ++ reg = <3 16>; ++ status = "okay"; ++ }; ++ }; ++ ++ /* Define these notional regulators for use by overlays, etc. */ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <3300000>; ++ regulator-name = "3v3"; ++ }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <5000000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-name = "5v0"; ++ }; ++}; ++ ++/ { ++ chosen: chosen { ++ bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe cgroup_disable=memory numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0"; ++ stdout-path = "serial10:115200n8"; ++ }; ++ ++ aliases: aliases { ++ blconfig = &blconfig; ++ blpubkey = &blpubkey; ++ bluetooth = &bluetooth; ++ console = &uart10; ++ drm-dsi1 = &dsi0; ++ drm-dsi2 = &dsi1; ++ ethernet0 = &rp1_eth; ++ fb = &fb; ++ gpio0 = &gpio; ++ gpio1 = &gio; ++ gpio2 = &gio_aon; ++ gpio3 = &pinctrl; ++ gpio4 = &pinctrl_aon; ++ gpiochip0 = &gpio; ++ gpiochip10 = &gio; ++ i2c = &i2c_arm; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c10 = &i2c_csi_dsi0; ++ i2c11 = &i2c_csi_dsi1; ++ i2c12 = &i2c_rp1boot; ++ mailbox = &mailbox; ++ mmc0 = &sdio1; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial10 = &uart10; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi10 = &spi10; ++ spi2 = &spi2; ++ spi3 = &spi3; ++ spi4 = &spi4; ++ spi5 = &spi5; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ uart10 = &uart10; ++ uart2 = &uart2; ++ uart3 = &uart3; ++ uart4 = &uart4; ++ usb0 = &rp1_usb0; ++ usb1 = &rp1_usb1; ++ wifi0 = &wifi; ++ }; ++ ++ __overrides__ { ++ act_led_gpio = <&led_act>,"gpios:4",<&led_act>,"gpios:0=",<&gpio>; ++ act_led_activelow = <&led_act>, "gpios:8"; ++ act_led_trigger = <&led_act>, "linux,default-trigger"; ++ axiperf = <&axiperf>,"status"; ++ bdaddr = <&bluetooth>, "local-bd-address["; ++ button_debounce = <&pwr_key>, "debounce-interval:0"; ++ cooling_fan = <&fan>, "status", <&rp1_pwm1>, "status"; ++ drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi; ++ drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0; ++ drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1; ++ drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4; ++ drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi; ++ drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0; ++ drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1; ++ drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4; ++ drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi; ++ drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0; ++ drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1; ++ drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4; ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; ++ fan_temp0 = <&cpu_tepid>,"temperature:0"; ++ fan_temp0_hyst = <&cpu_tepid>,"hysteresis:0"; ++ fan_temp0_speed = <&fan>, "cooling-levels:4"; ++ fan_temp1 = <&cpu_warm>,"temperature:0"; ++ fan_temp1_hyst = <&cpu_warm>,"hysteresis:0"; ++ fan_temp1_speed = <&fan>, "cooling-levels:8"; ++ fan_temp2 = <&cpu_hot>,"temperature:0"; ++ fan_temp2_hyst = <&cpu_hot>,"hysteresis:0"; ++ fan_temp2_speed = <&fan>, "cooling-levels:12"; ++ fan_temp3 = <&cpu_vhot>,"temperature:0"; ++ fan_temp3_hyst = <&cpu_vhot>,"hysteresis:0"; ++ fan_temp3_speed = <&fan>, "cooling-levels:16"; ++ i2c = <&i2c1>, "status"; ++ i2c_arm = <&i2c_arm>, "status"; ++ i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_baudrate = <&i2c_arm>, "clock-frequency:0"; ++ i2c_csi_dsi = <&i2c_csi_dsi>, "status"; ++ i2c_csi_dsi0 = <&i2c_csi_dsi0>, "status"; ++ i2c_csi_dsi1 = <&i2c_csi_dsi1>, "status"; ++ i2c_vc = <&i2c_vc>, "status"; ++ i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0"; ++ i2c0 = <&i2c0>, "status"; ++ i2c0_baudrate = <&i2c0>, "clock-frequency:0"; ++ i2c1 = <&i2c1>, "status"; ++ i2c1_baudrate = <&i2c1>, "clock-frequency:0"; ++ krnbt = <&bluetooth>, "status"; ++ nvme = <&pciex1>, "status"; ++ nvmem_cust_rw = <&nvmem_cust>,"rw?"; ++ nvmem_mac_rw = <&nvmem_mac>,"rw?"; ++ nvmem_priv_rw = <&nvmem_priv>,"rw?"; ++ pcie_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pciex1 = <&pciex1>, "status"; ++ pciex1_gen = <&pciex1> , "max-link-speed:0"; ++ pciex1_no_l0s = <&pciex1>, "aspm-no-l0s?"; ++ pciex1_tperst_clk_ms = <&pciex1>, "brcm,tperst-clk-ms:0"; ++ pwr_led_gpio = <&led_pwr>, "gpios:4"; ++ pwr_led_activelow = <&led_pwr>, "gpios:8"; ++ pwr_led_trigger = <&led_pwr>, "linux,default-trigger"; ++ random = <&random>, "status"; ++ rtc = <&rpi_rtc>, "status"; ++ rtc_bbat_vchg = <&rpi_rtc>, "trickle-charge-microvolt:0"; ++ spi = <&spi0>, "status"; ++ strict_gpiod = <&chosen>, "bootargs=pinctrl_rp1.persist_gpio_outputs=n"; ++ suspend = <&pwr_key>, "linux,code:0=205"; ++ uart0 = <&uart0>, "status"; ++ uart0_console = <&uart0>,"status", <&aliases>, "console=",&uart0; ++ wifiaddr = <&wifi>, "local-mac-address["; ++ ++ cam0_reg = <&cam0_reg>,"status"; ++ cam0_reg_gpio = <&cam0_reg>,"gpio:4", ++ <&cam0_reg>,"gpio:0=", <&gpio>; ++ cam1_reg = <&cam1_reg>,"status"; ++ cam1_reg_gpio = <&cam1_reg>,"gpio:4", ++ <&cam1_reg>,"gpio:0=", <&gpio>; ++ }; ++}; ++ ++pciex1: &pcie1 { }; ++pciex4: &pcie2 { }; ++ ++&dma32 { ++ /* The VPU firmware uses DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x03f>; ++}; ++ ++&dma40 { ++ /* The VPU firmware DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x07c0>; ++}; ++ ++&hdmi0 { ++ dmas = <&dma40 (10|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&hdmi1 { ++ dmas = <&dma40 (17|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&spi10 { ++ dmas = <&dma40 6>, <&dma40 7>; ++ dma-names = "tx", "rx"; ++}; ++ ++&usb { ++ power-domains = <&power RPI_POWER_DOMAIN_USB>; ++}; ++ ++&rmem { ++ /* ++ * RPi5's co-processor will copy the board's bootloader configuration ++ * into memory for the OS to consume. It'll also update this node with ++ * its placement information. ++ */ ++ blconfig: nvram@0 { ++ compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x0>; ++ no-map; ++ status = "disabled"; ++ }; ++ /* ++ * RPi5 will copy the binary public key blob (if present) from the bootloader ++ * into memory for use by the OS. ++ */ ++ blpubkey: nvram@1 { ++ compatible = "raspberrypi,bootloader-public-key", "nvmem-rmem"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x0>; ++ no-map; ++ status = "disabled"; ++ }; ++}; ++ ++&rp1_adc { ++ status = "okay"; ++}; ++ ++/* Add some gpiomem nodes to make the devices accessible to userspace. ++ * /dev/gpiomem should expose the registers for the interface with DT alias ++ * gpio. ++ */ ++ ++&rp1 { ++ gpiomem@d0000 { ++ /* Export IO_BANKs, RIO_BANKs and PADS_BANKs to userspace */ ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0xc0 0x400d0000 0x0 0x30000>; ++ chardev-name = "gpiomem0"; ++ }; ++}; ++ ++&soc { ++ gpiomem@7d508500 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d508500 0x40>; ++ chardev-name = "gpiomem1"; ++ }; ++ ++ gpiomem@7d517c00 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d517c00 0x40>; ++ chardev-name = "gpiomem2"; ++ }; ++ ++ gpiomem@7d504100 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d504100 0x20>; ++ chardev-name = "gpiomem3"; ++ }; ++ ++ gpiomem@7d510700 { ++ compatible = "raspberrypi,gpiomem"; ++ reg = <0x7d510700 0x20>; ++ chardev-name = "gpiomem4"; ++ }; ++ ++ sound: sound { ++ status = "disabled"; ++ }; ++}; ++ ++i2c0: &rp1_i2c0 { }; ++i2c1: &rp1_i2c1 { }; ++i2c2: &rp1_i2c2 { }; ++i2c3: &rp1_i2c3 { }; ++i2c4: &rp1_i2c4 { }; ++i2c5: &rp1_i2c5 { }; ++i2c6: &rp1_i2c6 { }; ++i2s: &rp1_i2s0 { }; ++i2s_clk_producer: &rp1_i2s0 { }; ++i2s_clk_consumer: &rp1_i2s1 { }; ++pwm0: &rp1_pwm0 { }; ++pwm1: &rp1_pwm1 { }; ++pwm: &pwm0 { }; ++spi0: &rp1_spi0 { }; ++spi1: &rp1_spi1 { }; ++spi2: &rp1_spi2 { }; ++spi3: &rp1_spi3 { }; ++spi4: &rp1_spi4 { }; ++spi5: &rp1_spi5 { }; ++ ++uart0_pins: &rp1_uart0_14_15 {}; ++uart0_ctsrts_pins: &rp1_uart0_ctsrts_16_17 {}; ++uart0: &rp1_uart0 { ++ pinctrl-0 = <&uart0_pins>; ++}; ++ ++uart1_pins: &rp1_uart1_0_1 {}; ++uart1_ctsrts_pins: &rp1_uart1_ctsrts_2_3 {}; ++uart1: &rp1_uart1 { }; ++ ++uart2_pins: &rp1_uart2_4_5 {}; ++uart2_ctsrts_pins: &rp1_uart2_ctsrts_6_7 {}; ++uart2: &rp1_uart2 { }; ++ ++uart3_pins: &rp1_uart3_8_9 {}; ++uart3_ctsrts_pins: &rp1_uart3_ctsrts_10_11 {}; ++uart3: &rp1_uart3 { }; ++ ++uart4_pins: &rp1_uart4_12_13 {}; ++uart4_ctsrts_pins: &rp1_uart4_ctsrts_14_15 {}; ++uart4: &rp1_uart4 { }; ++ ++i2c0_pins: &rp1_i2c0_0_1 {}; ++i2c_vc: &i2c0 { // This is pins 27,28 on the header (not MIPI) ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ clock-frequency = <100000>; ++}; ++ ++i2c1_pins: &rp1_i2c1_2_3 {}; ++i2c_arm: &i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ clock-frequency = <100000>; ++}; ++ ++i2c2_pins: &rp1_i2c2_4_5 {}; ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins>; ++}; ++ ++i2c3_pins: &rp1_i2c3_6_7 {}; ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pins>; ++}; ++ ++&i2s_clk_producer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s0_18_21>; ++}; ++ ++&i2s_clk_consumer { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rp1_i2s1_18_21>; ++}; ++ ++spi0_pins: &rp1_spi0_gpio9 {}; ++spi0_cs_pins: &rp1_spi0_cs_gpio7 {}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; ++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; ++ ++ spidev0: spidev@0 { ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++ ++ spidev1: spidev@1 { ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++}; ++ ++spi2_pins: &rp1_spi2_gpio1 {}; ++&spi2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi2_pins>; ++}; ++ ++spi3_pins: &rp1_spi3_gpio5 {}; ++&spi3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi3_pins>; ++}; ++ ++spi4_pins: &rp1_spi4_gpio9 {}; ++&spi4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi4_pins>; ++}; ++ ++spi5_pins: &rp1_spi5_gpio13 {}; ++&spi5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi5_pins>; ++}; +diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +new file mode 100644 +index 000000000000..f4360daae488 +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -0,0 +1,1308 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2712", "brcm,bcm2711"; ++ model = "BCM2712"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gicv2>; ++ ++ rmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges; ++ ++ atf@0 { ++ reg = <0x0 0x0 0x80000>; ++ no-map; ++ }; ++ ++ cma: linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x4000000>; /* 64MB */ ++ reusable; ++ linux,cma-default; ++ ++ /* ++ * arm64 reserves the CMA by default somewhere in ++ * ZONE_DMA32, that's not good enough for the BCM2711 ++ * as some devices can only address the lower 1G of ++ * memory (ZONE_DMA). ++ */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <1000>; ++ coefficients = <(-550) 450000>; ++ thermal-sensors = <&thermal>; ++ ++ thermal_trips: trips { ++ cpu_crit: cpu-crit { ++ temperature = <110000>; ++ hysteresis = <0>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling_maps: cooling-maps { ++ }; ++ }; ++ }; ++ ++ clk_27MHz: clk-27M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <27000000>; ++ clock-output-names = "27MHz-clock"; ++ }; ++ ++ clk_108MHz: clk-108M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <108000000>; ++ clock-output-names = "108MHz-clock"; ++ }; ++ ++ hvs: hvs@107c580000 { ++ compatible = "brcm,bcm2712-hvs"; ++ reg = <0x10 0x7c580000 0x1a000>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <2>, <9>, <16>; ++ interrupt-names = "ch0-eof", "ch1-eof", "ch2-eof"; ++ //iommus = <&iommu4>; ++ status = "disabled"; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ranges = <0x7c000000 0x10 0x7c000000 0x04000000>; ++ /* Emulate a contiguous 30-bit address range for DMA */ ++ dma-ranges = <0xc0000000 0x00 0x00000000 0x40000000>, ++ <0x7c000000 0x10 0x7c000000 0x04000000>; ++ ++ system_timer: timer@7c003000 { ++ compatible = "brcm,bcm2835-system-timer"; ++ reg = <0x7c003000 0x1000>; ++ interrupts = , ++ , ++ , ++ ; ++ clock-frequency = <1000000>; ++ }; ++ ++ firmwarekms: firmwarekms@7d503000 { ++ compatible = "raspberrypi,rpi-firmware-kms-2712"; ++ /* SUN_L2 interrupt reg */ ++ reg = <0x7d503000 0x18>; ++ interrupt-parent = <&cpu_l2_irq>; ++ interrupts = <19>; ++ brcm,firmware = <&firmware>; ++ status = "disabled"; ++ }; ++ ++ axiperf: axiperf { ++ compatible = "brcm,bcm2712-axiperf"; ++ reg = <0x7c012800 0x100>, ++ <0x7e000000 0x100>; ++ firmware = <&firmware>; ++ status = "disabled"; ++ }; ++ ++ mailbox: mailbox@7c013880 { ++ compatible = "brcm,bcm2835-mbox"; ++ reg = <0x7c013880 0x40>; ++ interrupts = ; ++ #mbox-cells = <0>; ++ }; ++ ++ pixelvalve0: pixelvalve@7c410000 { ++ compatible = "brcm,bcm2712-pixelvalve0"; ++ reg = <0x7c410000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pixelvalve1: pixelvalve@7c411000 { ++ compatible = "brcm,bcm2712-pixelvalve1"; ++ reg = <0x7c411000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ mop: mop@7c500000 { ++ compatible = "brcm,bcm2712-mop"; ++ reg = <0x7c500000 0x28>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <1>; ++ status = "disabled"; ++ }; ++ ++ moplet: moplet@7c501000 { ++ compatible = "brcm,bcm2712-moplet"; ++ reg = <0x7c501000 0x20>; ++ interrupt-parent = <&disp_intr>; ++ interrupts = <0>; ++ status = "disabled"; ++ }; ++ ++ disp_intr: interrupt-controller@7c502000 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7c502000 0x30>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ dvp: clock@7c700000 { ++ compatible = "brcm,brcm2711-dvp"; ++ reg = <0x7c700000 0x10>; ++ clocks = <&clk_108MHz>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ /* ++ * This node is the provider for the enable-method for ++ * bringing up secondary cores. ++ */ ++ local_intc: local_intc@7cd00000 { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x7cd00000 0x100>; ++ }; ++ ++ uart0: serial@7d001000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001000 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@7d001400 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001400 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@7d001a00 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7d001a00 0x200>; ++ interrupts = ; ++ clocks = <&clk_uart>, ++ <&clk_vpu>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ sdhost: mmc@7d002000 { ++ compatible = "brcm,bcm2835-sdhost"; ++ reg = <0x7d002000 0x100>; ++ //interrupts = ; ++ clocks = <&clk_vpu>; ++ status = "disabled"; ++ }; ++ ++ i2s: i2s@7d003000 { ++ compatible = "brcm,bcm2835-i2s"; ++ reg = <0x7d003000 0x24>; ++ //clocks = <&cprman BCM2835_CLOCK_PCM>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi@7d004000 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004000 0x200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ num-cs = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@7d004600 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004600 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7d004800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004800 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7d004a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004a00 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7d004c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7d004c00 0x0200>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@7d005000 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005000 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@7d005600 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005600 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@7d005800 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005800 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@7d005a00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005a00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@7d005c00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005c00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c8: i2c@7d005e00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7d005e00 0x20>; ++ interrupts = ; ++ clocks = <&clk_vpu>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm0: pwm@7d00c000 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c000 0x28>; ++ assigned-clock-rates = <50000000>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@7d00c800 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7d00c800 0x28>; ++ assigned-clock-rates = <50000000>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pm: watchdog@7d200000 { ++ compatible = "brcm,bcm2712-pm"; ++ reg = <0x7d200000 0x308>; ++ reg-names = "pm"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ //clocks = <&cprman BCM2835_CLOCK_V3D>, ++ // <&cprman BCM2835_CLOCK_PERI_IMAGE>, ++ // <&cprman BCM2835_CLOCK_H264>, ++ // <&cprman BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ ++ cprman: cprman@7d202000 { ++ compatible = "brcm,bcm2711-cprman"; ++ reg = <0x7d202000 0x2000>; ++ #clock-cells = <1>; ++ ++ /* CPRMAN derives almost everything from the ++ * platform's oscillator. However, the DSI ++ * pixel clocks come from the DSI analog PHY. ++ */ ++ clocks = <&clk_osc>; ++ status = "disabled"; ++ }; ++ ++ random: rng@7d208000 { ++ compatible = "brcm,bcm2711-rng200"; ++ reg = <0x7d208000 0x28>; ++ status = "okay"; ++ }; ++ ++ cpu_l2_irq: intc@7d503000 { ++ compatible = "brcm,l2-intc"; ++ reg = <0x7d503000 0x18>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ pinctrl: pinctrl@7d504100 { ++ compatible = "brcm,bcm2712-pinctrl"; ++ reg = <0x7d504100 0x30>; ++ ++ uarta_24_pins: uarta_24_pins { ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio24"; ++ bias-disable; ++ }; ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio25"; ++ bias-pull-up; ++ }; ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio26"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio27"; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdio2_30_pins: sdio2_30_pins { ++ pin_clk { ++ function = "sd2"; ++ pins = "gpio30"; ++ bias-disable; ++ }; ++ pin_cmd { ++ function = "sd2"; ++ pins = "gpio31"; ++ bias-pull-up; ++ }; ++ pins_dat { ++ function = "sd2"; ++ pins = "gpio32", "gpio33", "gpio34", "gpio35"; ++ bias-pull-up; ++ }; ++ }; ++ }; ++ ++ ddc0: i2c@7d508200 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508200 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <1>; ++ clock-frequency = <97500>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ ddc1: i2c@7d508280 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508280 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <2>; ++ clock-frequency = <97500>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bscd: i2c@7d508300 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d508300 0x58>; ++ interrupt-parent = <&bsc_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ bsc_irq: intc@7d508380 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508380 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ main_irq: intc@7d508400 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d508400 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio: gpio@7d508500 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d508500 0x40>; ++ interrupt-parent = <&main_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <32 22>; ++ brcm,gpio-direct; ++ }; ++ ++ uarta: serial@7d50c000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50c000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ uartb: serial@7d50d000 { ++ compatible = "brcm,bcm7271-uart"; ++ reg = <0x7d50d000 0x20>; ++ reg-names = "uart"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ interrupts = ; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ aon_intr: interrupt-controller@7d510600 { ++ compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; ++ reg = <0x7d510600 0x30>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ pinctrl_aon: pinctrl@7d510700 { ++ compatible = "brcm,bcm2712-aon-pinctrl"; ++ reg = <0x7d510700 0x20>; ++ ++ i2c3_m4_agpio0_pins: i2c3_m4_agpio0_pins { ++ function = "vc_i2c3"; ++ pins = "aon_gpio0", "aon_gpio1"; ++ bias-pull-up; ++ }; ++ ++ bsc_m1_agpio13_pins: bsc_m1_agpio13_pins { ++ function = "bsc_m1"; ++ pins = "aon_gpio13", "aon_gpio14"; ++ bias-pull-up; ++ }; ++ ++ bsc_pmu_sgpio4_pins: bsc_pmu_sgpio4_pins { ++ function = "avs_pmu_bsc"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ bsc_m2_sgpio4_pins: bsc_m2_sgpio4_pins { ++ function = "bsc_m2"; ++ pins = "aon_sgpio4", "aon_sgpio5"; ++ }; ++ ++ pwm_aon_agpio1_pins: pwm_aon_agpio1_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio1", "aon_gpio2"; ++ }; ++ ++ pwm_aon_agpio4_pins: pwm_aon_agpio4_pins { ++ function = "vc_pwm0"; ++ pins = "aon_gpio4", "aon_gpio5"; ++ }; ++ ++ pwm_aon_agpio7_pins: pwm_aon_agpio7_pins { ++ function = "aon_pwm"; ++ pins = "aon_gpio7", "aon_gpio9"; ++ }; ++ }; ++ ++ intc@7d517000 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517000 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ bscc: i2c@7d517a00 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d517a00 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <0>; ++ clock-frequency = <200000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm_aon: pwm@7d517a80 { ++ compatible = "brcm,bcm7038-pwm"; ++ reg = <0x7d517a80 0x28>; ++ #pwm-cells = <3>; ++ clocks = <&clk_27MHz>; ++ }; ++ ++ main_aon_irq: intc@7d517ac0 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517ac0 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ bsc_aon_irq: intc@7d517b00 { ++ compatible = "brcm,bcm7271-l2-intc"; ++ reg = <0x7d517b00 0x10>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ ++ gio_aon: gpio@7d517c00 { ++ compatible = "brcm,brcmstb-gpio"; ++ reg = <0x7d517c00 0x40>; ++ interrupt-parent = <&main_aon_irq>; ++ interrupts = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,gpio-bank-widths = <17 6>; ++ brcm,gpio-direct; ++ }; ++ ++ avs_monitor: avs-monitor@7d542000 { ++ compatible = "brcm,bcm2711-avs-monitor", ++ "syscon", "simple-mfd"; ++ reg = <0x7d542000 0xf00>; ++ status = "okay"; ++ ++ thermal: thermal { ++ compatible = "brcm,bcm2711-thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ }; ++ ++ bsc_pmu: i2c@7d544000 { ++ compatible = "brcm,brcmstb-i2c"; ++ reg = <0x7d544000 0x58>; ++ interrupt-parent = <&bsc_aon_irq>; ++ interrupts = <1>; ++ clock-frequency = <200000>; ++ status = "disabled"; ++ }; ++ ++ hdmi0: hdmi@7ef00700 { ++ compatible = "brcm,bcm2712-hdmi0"; ++ reg = <0x7c701400 0x300>, ++ <0x7c701000 0x200>, ++ <0x7c701d00 0x300>, ++ <0x7c702000 0x80>, ++ <0x7c703800 0x200>, ++ <0x7c704000 0x800>, ++ <0x7c700100 0x80>, ++ <0x7d510800 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ resets = <&dvp 1>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <1>, <2>, <3>, ++ <7>, <8>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ ddc = <&ddc0>; ++ dmas = <&dma32 10>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ ++ hdmi1: hdmi@7ef05700 { ++ compatible = "brcm,bcm2712-hdmi1"; ++ reg = <0x7c706400 0x300>, ++ <0x7c706000 0x200>, ++ <0x7c706d00 0x300>, ++ <0x7c707000 0x80>, ++ <0x7c708800 0x200>, ++ <0x7c709000 0x800>, ++ <0x7c700180 0x80>, ++ <0x7d511000 0x100>, ++ <0x7c720000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ ddc = <&ddc1>; ++ resets = <&dvp 2>; ++ interrupt-parent = <&aon_intr>; ++ interrupts = <11>, <12>, <13>, ++ <14>, <15>; ++ interrupt-names = "cec-tx", "cec-rx", "cec-low", ++ "hpd-connected", "hpd-removed"; ++ dmas = <&dma32 17>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a76-pmu"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ /* This only applies to the ARMv7 stub */ ++ arm,cpu-registers-not-fw-configured; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit ++ ++ /* Source for d/i cache-line-size, cache-sets, cache-size ++ * https://developer.arm.com/documentation/100798/0401 ++ * /L1-memory-system/About-the-L1-memory-system?lang=en ++ */ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x000>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l0>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x100>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l1>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x200>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l2>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a76"; ++ reg = <0x300>; ++ enable-method = "psci"; ++ d-cache-size = <0x10000>; ++ d-cache-line-size = <64>; ++ d-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ i-cache-size = <0x10000>; ++ i-cache-line-size = <64>; ++ i-cache-sets = <256>; // 64KiB(size)/64(line-size)=1024ways/4-way set ++ next-level-cache = <&l2_cache_l3>; ++ }; ++ ++ /* Source for cache-line-size and cache-sets: ++ * https://developer.arm.com/documentation/100798/0401 ++ * /L2-memory-system/About-the-L2-memory-system?lang=en ++ * and for cache-size: ++ * https://www.raspberrypi.com/documentation/computers ++ * /processors.html#bcm2712 ++ */ ++ l2_cache_l0: l2-cache-l0 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l1: l2-cache-l1 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l2: l2-cache-l2 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ l2_cache_l3: l2-cache-l3 { ++ compatible = "cache"; ++ cache-size = <0x80000>; ++ cache-line-size = <128>; ++ cache-sets = <1024>; // 512KiB(size)/64(line-size)=8192ways/8-way set ++ cache-level = <2>; ++ cache-unified; ++ next-level-cache = <&l3_cache>; ++ }; ++ ++ /* Source for cache-line-size and cache-sets: ++ * https://developer.arm.com/documentation/100453/0401/L3-cache?lang=en ++ * Source for cache-size: ++ * https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712 ++ */ ++ l3_cache: l3-cache { ++ compatible = "cache"; ++ cache-size = <0x200000>; ++ cache-line-size = <64>; ++ cache-sets = <2048>; // 2MiB(size)/64(line-size)=32768ways/16-way set ++ cache-level = <3>; ++ }; ++ }; ++ ++ psci { ++ method = "smc"; ++ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; ++ cpu_on = <0xc4000003>; ++ cpu_suspend = <0xc4000001>; ++ cpu_off = <0x84000002>; ++ }; ++ ++ axi: axi { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ dma-ranges = <0x00 0x00000000 0x00 0x00000000 0x10 0x00000000>, ++ <0x10 0x00000000 0x10 0x00000000 0x01 0x00000000>, ++ <0x14 0x00000000 0x14 0x00000000 0x04 0x00000000>, ++ <0x18 0x00000000 0x18 0x00000000 0x04 0x00000000>, ++ <0x1c 0x00000000 0x1c 0x00000000 0x04 0x00000000>; ++ ++ vc4: gpu { ++ compatible = "brcm,bcm2712-vc6"; ++ }; ++ ++ iommu2: iommu@5100 { ++ /* IOMMU2 for PISP-BE, HEVC; and (unused) H264 accelerators */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5100 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ }; ++ ++ iommu4: iommu@5200 { ++ /* IOMMU4 for HVS, MPL/TXP; and (unused) Unicam, PISP-FE, MiniBVN */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5200 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ #interconnect-cells = <0>; ++ }; ++ ++ iommu5: iommu@5280 { ++ /* IOMMU5 for PCIe2 (RP1); and (unused) BSTM */ ++ compatible = "brcm,bcm2712-iommu"; ++ reg = <0x10 0x5280 0x0 0x80>; ++ cache = <&iommuc>; ++ #iommu-cells = <0>; ++ dma-iova-offset = <0x10 0x00000000>; // HACK for RP1 masters over PCIe ++ }; ++ ++ iommuc: iommuc@5b00 { ++ compatible = "brcm,bcm2712-iommuc"; ++ reg = <0x10 0x5b00 0x0 0x80>; ++ }; ++ ++ dma32: dma@10000 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010000 0 0x600>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0035>; ++ }; ++ ++ dma40: dma@10600 { ++ compatible = "brcm,bcm2712-dma"; ++ reg = <0x10 0x00010600 0 0x600>; ++ interrupts = ++ , /* dma4 6 */ ++ , /* dma4 7 */ ++ , /* dma4 8 */ ++ , /* dma4 9 */ ++ , /* dma4 10 */ ++ ; /* dma4 11 */ ++ interrupt-names = "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10", ++ "dma11"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x0fc0>; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x14_000000-0x17_ffffff ++ pcie0: pcie@100000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00100000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 208: AER ++ * 215: NMI ++ * 216: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 209 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 210 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 211 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 212 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 5>, <&bcm_reset 42>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&pcie0>; ++ ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x17 0x00000000 ++ 0x0 0xfffffffc>, ++ <0x43000000 0x04 0x00000000 ++ 0x14 0x00000000 ++ 0x3 0x00000000>; ++ ++ dma-ranges = <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ status = "disabled"; ++ }; ++ ++ // Single-lane Gen3 PCIe ++ // Outbound window at 0x18_000000-0x1b_ffffff ++ pcie1: pcie@110000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00110000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 218: AER ++ * 225: NMI ++ * 226: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 219 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 220 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 221 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 222 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 7>, <&bcm_reset 43>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip1>; ++ ++ // 2GB, 32-bit, non-prefetchable at PCIe 00_80000000 ++ ranges = <0x02000000 0x00 0x80000000 ++ 0x1b 0x80000000 ++ 0x00 0x80000000>, ++ // 14GB, 64-bit, prefetchable at PCIe 04_00000000 ++ <0x43000000 0x04 0x00000000 ++ 0x18 0x00000000 ++ 0x03 0x80000000>; ++ ++ dma-ranges = <0x03000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ status = "disabled"; ++ }; ++ ++ pcie_rescal: reset-controller@119500 { ++ compatible = "brcm,bcm7216-pcie-sata-rescal"; ++ reg = <0x10 0x00119500 0x0 0x10>; ++ #reset-cells = <0>; ++ }; ++ ++ // Quad-lane Gen3 PCIe ++ // Outbound window at 0x1c_000000-0x1f_ffffff ++ pcie2: pcie@120000 { ++ compatible = "brcm,bcm2712-pcie"; ++ reg = <0x10 0x00120000 0x0 0x9310>; ++ device_type = "pci"; ++ max-link-speed = <2>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ /* ++ * Unused interrupts: ++ * 228: AER ++ * 235: NMI ++ * 236: PME ++ */ ++ interrupt-parent = <&gicv2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 229 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &gicv2 GIC_SPI 230 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &gicv2 GIC_SPI 231 ++ IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &gicv2 GIC_SPI 232 ++ IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&bcm_reset 32>, <&bcm_reset 44>, <&pcie_rescal>; ++ reset-names = "swinit", "bridge", "rescal"; ++ msi-controller; ++ msi-parent = <&mip0>; ++ ++ // ~4GB, 32-bit, not-prefetchable at PCIe 00_00000000 ++ ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x0 0xfffffffc>, ++ // 12GB, 64-bit, prefetchable at PCIe 04_00000000 ++ <0x43000000 0x04 0x00000000 ++ 0x1c 0x00000000 ++ 0x03 0x00000000>; ++ ++ // 64GB system RAM space at PCIe 10_00000000 ++ dma-ranges = <0x02000000 0x00 0x00000000 ++ 0x1f 0x00000000 ++ 0x00 0x00400000>, ++ <0x43000000 0x10 0x00000000 ++ 0x00 0x00000000 ++ 0x10 0x00000000>; ++ ++ status = "disabled"; ++ }; ++ ++ mip0: msi-controller@130000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00130000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <128>; ++ brcm,msi-num-spis = <64>; ++ brcm,msi-offset = <0>; ++ brcm,msi-pci-addr = <0xff 0xfffff000>; ++ }; ++ ++ mip1: msi-controller@131000 { ++ compatible = "brcm,bcm2712-mip-intc"; ++ reg = <0x10 0x00131000 0x0 0xc0>; ++ msi-controller; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ brcm,msi-base-spi = <247>; ++ /* Actually 20 total, but the others are ++ * both sparse and non-consecutive */ ++ brcm,msi-num-spis = <8>; ++ brcm,msi-offset = <8>; ++ brcm,msi-pci-addr = <0xff 0xffffe000>; ++ }; ++ ++ syscon_piarbctl: syscon@400018 { ++ compatible = "brcm,syscon-piarbctl", "syscon", "simple-mfd"; ++ reg = <0x10 0x00400018 0x0 0x18>; ++ }; ++ ++ usb: usb@480000 { ++ compatible = "brcm,bcm2835-usb"; ++ reg = <0x10 0x00480000 0x0 0x10000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk_usb>; ++ clock-names = "otg"; ++ phys = <&usbphy>; ++ phy-names = "usb2-phy"; ++ status = "disabled"; ++ }; ++ ++ rpivid: codec@800000 { ++ compatible = "raspberrypi,rpivid-vid-decoder"; ++ reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ ++ <0x10 0x00840000 0x0 0x1000>; /* INTC */ ++ reg-names = "hevc", ++ "intc"; ++ ++ interrupts = ; ++ ++ clocks = <&firmware_clocks 11>; ++ clock-names = "hevc"; ++ iommus = <&iommu2>; ++ status = "disabled"; ++ }; ++ ++ sdio1: mmc@fff000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x00fff000 0x0 0x260>, ++ <0x10 0x00fff400 0x0 0x200>, ++ <0x10 0x015040b0 0x0 0x4>, // Bus isolation control ++ <0x10 0x015200f0 0x0 0x24>; // LCPLL control misc0-8 ++ reg-names = "host", "cfg", "busisol", "lcpll"; ++ interrupts = ; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ mmc-ddr-3_3v; ++ }; ++ ++ sdio2: mmc@1100000 { ++ compatible = "brcm,bcm2712-sdhci"; ++ reg = <0x10 0x01100000 0x0 0x260>, ++ <0x10 0x01100400 0x0 0x200>; ++ reg-names = "host", "cfg"; ++ interrupts = ; ++ clocks = <&clk_emmc2>; ++ sdhci-caps-mask = <0x0000C000 0x0>; ++ sdhci-caps = <0x0 0x0>; ++ supports-cqe; ++ mmc-ddr-3_3v; ++ status = "disabled"; ++ }; ++ ++ bcm_reset: reset-controller@1504318 { ++ compatible = "brcm,brcmstb-reset"; ++ reg = <0x10 0x01504318 0x0 0x30>; ++ #reset-cells = <1>; ++ }; ++ ++ v3d: v3d@2000000 { ++ compatible = "brcm,2712-v3d"; ++ reg = <0x10 0x02000000 0x0 0x4000>, ++ <0x10 0x02008000 0x0 0x6000>; ++ reg-names = "hub", "core0"; ++ ++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; ++ resets = <&pm BCM2835_RESET_V3D>; ++ clocks = <&firmware_clocks 5>; ++ clocks-names = "v3d"; ++ interrupts = , ++ ; ++ status = "disabled"; ++ }; ++ ++ gicv2: interrupt-controller@7fff9000 { ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ compatible = "arm,gic-400"; ++ reg = <0x10 0x7fff9000 0x0 0x1000>, ++ <0x10 0x7fffa000 0x0 0x2000>, ++ <0x10 0x7fffc000 0x0 0x2000>, ++ <0x10 0x7fffe000 0x0 0x2000>; ++ interrupts = ; ++ }; ++ ++ pisp_be: pisp_be@880000 { ++ compatible = "raspberrypi,pispbe"; ++ reg = <0x10 0x00880000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&firmware_clocks 7>; ++ clocks-names = "isp_be"; ++ status = "okay"; ++ iommus = <&iommu2>; ++ }; ++ }; ++ ++ clocks { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* The oscillator is the root of the clock tree. */ ++ clk_osc: clk-osc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "osc"; ++ clock-frequency = <54000000>; ++ }; ++ ++ clk_usb: clk-usb { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "otg"; ++ clock-frequency = <480000000>; ++ }; ++ ++ clk_vpu: clk_vpu { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <750000000>; ++ clock-output-names = "vpu-clock"; ++ }; ++ ++ clk_uart: clk_uart { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <9216000>; ++ clock-output-names = "uart-clock"; ++ }; ++ ++ clk_emmc2: clk_emmc2 { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <200000000>; ++ clock-output-names = "emmc2-clock"; ++ }; ++ }; ++ ++ usbphy: phy { ++ compatible = "usb-nop-xceiv"; ++ #phy-cells = <0>; ++ }; ++}; diff --git a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts new file mode 100644 -index 000000000000..9b3ddbb8dafd +index 000000000000..d06536bc7592 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts -@@ -0,0 +1,2 @@ +@@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 -+#include "../../../../arm/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts" -diff --git a/arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi b/arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi -new file mode 120000 -index 000000000000..e5c400284467 ++#include "bcm2712-rpi-5-b.dts" ++ ++&gio { ++ brcm,gpio-bank-widths = <32 4>; ++ ++ gpio-line-names = ++ "", // GPIO_000 ++ "2712_BOOT_CS_N", // GPIO_001 ++ "2712_BOOT_MISO", // GPIO_002 ++ "2712_BOOT_MOSI", // GPIO_003 ++ "2712_BOOT_SCLK", // GPIO_004 ++ "", // GPIO_005 ++ "", // GPIO_006 ++ "", // GPIO_007 ++ "", // GPIO_008 ++ "", // GPIO_009 ++ "-", // GPIO_010 ++ "-", // GPIO_011 ++ "-", // GPIO_012 ++ "-", // GPIO_013 ++ "PCIE_SDA", // GPIO_014 ++ "PCIE_SCL", // GPIO_015 ++ "", // GPIO_016 ++ "", // GPIO_017 ++ "-", // GPIO_018 ++ "-", // GPIO_019 ++ "PWR_GPIO", // GPIO_020 ++ "2712_G21_FS", // GPIO_021 ++ "-", // GPIO_022 ++ "-", // GPIO_023 ++ "BT_RTS", // GPIO_024 ++ "BT_CTS", // GPIO_025 ++ "BT_TXD", // GPIO_026 ++ "BT_RXD", // GPIO_027 ++ "WL_ON", // GPIO_028 ++ "BT_ON", // GPIO_029 ++ "WIFI_SDIO_CLK", // GPIO_030 ++ "WIFI_SDIO_CMD", // GPIO_031 ++ "WIFI_SDIO_D0", // GPIO_032 ++ "WIFI_SDIO_D1", // GPIO_033 ++ "WIFI_SDIO_D2", // GPIO_034 ++ "WIFI_SDIO_D3"; // GPIO_035 ++}; ++ ++&gio_aon { ++ brcm,gpio-bank-widths = <15 6>; ++ ++ gpio-line-names = ++ "RP1_SDA", // AON_GPIO_00 ++ "RP1_SCL", // AON_GPIO_01 ++ "RP1_RUN", // AON_GPIO_02 ++ "SD_IOVDD_SEL", // AON_GPIO_03 ++ "SD_PWR_ON", // AON_GPIO_04 ++ "SD_CDET_N", // AON_GPIO_05 ++ "SD_FLG_N", // AON_GPIO_06 ++ "", // AON_GPIO_07 ++ "2712_WAKE", // AON_GPIO_08 ++ "2712_STAT_LED", // AON_GPIO_09 ++ "", // AON_GPIO_10 ++ "", // AON_GPIO_11 ++ "PMIC_INT", // AON_GPIO_12 ++ "UART_TX_FS", // AON_GPIO_13 ++ "UART_RX_FS", // AON_GPIO_14 ++ "", // AON_GPIO_15 ++ "", // AON_GPIO_16 ++ ++ // Pad bank0 out to 32 entries ++ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ++ ++ "HDMI0_SCL", // AON_SGPIO_00 ++ "HDMI0_SDA", // AON_SGPIO_01 ++ "HDMI1_SCL", // AON_SGPIO_02 ++ "HDMI1_SDA", // AON_SGPIO_03 ++ "PMIC_SCL", // AON_SGPIO_04 ++ "PMIC_SDA"; // AON_SGPIO_05 ++}; ++ ++&pinctrl { ++ compatible = "brcm,bcm2712d0-pinctrl"; ++ reg = <0x7d504100 0x20>; ++}; ++ ++&pinctrl_aon { ++ compatible = "brcm,bcm2712d0-aon-pinctrl"; ++ reg = <0x7d510700 0x1c>; ++}; ++ ++&vc4 { ++ compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6"; ++}; ++ ++&uart10 { ++ interrupts = ; ++}; ++ ++&spi10 { ++ dmas = <&dma40 3>, <&dma40 4>; ++}; ++ ++&hdmi0 { ++ dmas = <&dma40 (12|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; ++ ++&hdmi1 { ++ dmas = <&dma40 (13|(1<<30)|(1<<24)|(10<<16)|(15<<20))>; ++}; +diff --git a/arch/arm64/boot/dts/broadcom/rp1.dtsi b/arch/arm64/boot/dts/broadcom/rp1.dtsi +new file mode 100644 +index 000000000000..1f60f3f03a10 --- /dev/null -+++ b/arch/arm64/boot/dts/broadcom/bcm283x-rpi-csi1-2lane.dtsi -@@ -0,0 +1 @@ -+../../../../arm/boot/dts/bcm283x-rpi-csi1-2lane.dtsi -\ No newline at end of file -diff --git a/arch/arm64/boot/dts/broadcom/bcm283x-rpi-lan7515.dtsi b/arch/arm64/boot/dts/broadcom/bcm283x-rpi-lan7515.dtsi -new file mode 120000 -index 000000000000..fc4c05bbe7fd ---- /dev/null -+++ b/arch/arm64/boot/dts/broadcom/bcm283x-rpi-lan7515.dtsi -@@ -0,0 +1 @@ -+../../../../arm/boot/dts/bcm283x-rpi-lan7515.dtsi -\ No newline at end of file ++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi +@@ -0,0 +1,1289 @@ ++#include ++#include ++#include ++ ++&rp1_target { ++ rp1: rp1 { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ #interrupt-cells = <2>; ++ interrupt-controller; ++ interrupt-parent = <&rp1>; ++ ++ // ranges and dma-ranges must be provided by the includer ++ ++ rp1_clocks: clocks@18000 { ++ compatible = "raspberrypi,rp1-clocks"; ++ #clock-cells = <1>; ++ reg = <0xc0 0x40018000 0x0 0x10038>; ++ clocks = <&clk_xosc>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_SYS_CORE>, ++ <&rp1_clocks RP1_PLL_AUDIO_CORE>, ++ // RP1_PLL_VIDEO_CORE and dividers are now managed by VEC,DPI drivers ++ <&rp1_clocks RP1_PLL_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_SEC>, ++ <&rp1_clocks RP1_PLL_AUDIO>, ++ <&rp1_clocks RP1_PLL_AUDIO_SEC>, ++ <&rp1_clocks RP1_CLK_SYS>, ++ <&rp1_clocks RP1_PLL_SYS_PRI_PH>, ++ // RP1_CLK_SLOW_SYS is used for the frequency counter (FC0) ++ <&rp1_clocks RP1_CLK_SLOW_SYS>, ++ <&rp1_clocks RP1_CLK_SDIO_TIMER>, ++ <&rp1_clocks RP1_CLK_SDIO_ALT_SRC>, ++ <&rp1_clocks RP1_CLK_ETH_TSU>; ++ ++ assigned-clock-rates = <1000000000>, // RP1_PLL_SYS_CORE ++ <1536000000>, // RP1_PLL_AUDIO_CORE ++ <200000000>, // RP1_PLL_SYS ++ <125000000>, // RP1_PLL_SYS_SEC ++ <61440000>, // RP1_PLL_AUDIO ++ <192000000>, // RP1_PLL_AUDIO_SEC ++ <200000000>, // RP1_CLK_SYS ++ <100000000>, // RP1_PLL_SYS_PRI_PH ++ // Must match the XOSC frequency ++ <50000000>, // RP1_CLK_SLOW_SYS ++ <1000000>, // RP1_CLK_SDIO_TIMER ++ <200000000>, // RP1_CLK_SDIO_ALT_SRC ++ <50000000>; // RP1_CLK_ETH_TSU ++ }; ++ ++ rp1_uart0: serial@30000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40030000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART0_TX>, ++ // <&rp1_dma RP1_DMA_UART0_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart1: serial@34000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40034000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART1_TX>, ++ // <&rp1_dma RP1_DMA_UART1_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart2: serial@38000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40038000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART2_TX>, ++ // <&rp1_dma RP1_DMA_UART2_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart3: serial@3c000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x4003c000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART3_TX>, ++ // <&rp1_dma RP1_DMA_UART3_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart4: serial@40000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40040000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART4_TX>, ++ // <&rp1_dma RP1_DMA_UART4_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_uart5: serial@44000 { ++ compatible = "arm,pl011-axi"; ++ reg = <0xc0 0x40044000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_UART &rp1_clocks RP1_PLL_SYS_PRI_PH>; ++ clock-names = "uartclk", "apb_pclk"; ++ // dmas = <&rp1_dma RP1_DMA_UART5_TX>, ++ // <&rp1_dma RP1_DMA_UART5_RX>; ++ // dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ arm,primecell-periphid = <0x00541011>; ++ uart-has-rtscts; ++ cts-event-workaround; ++ skip-init; ++ status = "disabled"; ++ }; ++ ++ rp1_spi8: spi@4c000 { ++ reg = <0xc0 0x4004c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI8_TX>, ++ <&rp1_dma RP1_DMA_SPI8_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi0: spi@50000 { ++ reg = <0xc0 0x40050000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI0_TX>, ++ <&rp1_dma RP1_DMA_SPI0_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi1: spi@54000 { ++ reg = <0xc0 0x40054000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI1_TX>, ++ <&rp1_dma RP1_DMA_SPI1_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi2: spi@58000 { ++ reg = <0xc0 0x40058000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI2_TX>, ++ <&rp1_dma RP1_DMA_SPI2_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi3: spi@5c000 { ++ reg = <0xc0 0x4005c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI3_TX>, ++ <&rp1_dma RP1_DMA_SPI3_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI4 is a target/slave interface ++ rp1_spi4: spi@60000 { ++ reg = <0xc0 0x40060000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI4_TX>, ++ <&rp1_dma RP1_DMA_SPI4_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_spi5: spi@64000 { ++ reg = <0xc0 0x40064000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI5_TX>, ++ <&rp1_dma RP1_DMA_SPI5_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ rp1_spi6: spi@68000 { ++ reg = <0xc0 0x40068000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ num-cs = <2>; ++ dmas = <&rp1_dma RP1_DMA_SPI6_TX>, ++ <&rp1_dma RP1_DMA_SPI6_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ // SPI7 is a target/slave interface ++ rp1_spi7: spi@6c000 { ++ reg = <0xc0 0x4006c000 0x0 0x130>; ++ compatible = "snps,dw-apb-ssi"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ clock-names = "ssi_clk"; ++ #address-cells = <0>; ++ #size-cells = <0>; ++ num-cs = <1>; ++ spi-slave; ++ dmas = <&rp1_dma RP1_DMA_SPI7_TX>, ++ <&rp1_dma RP1_DMA_SPI7_RX>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ ++ slave { ++ compatible = "spidev"; ++ spi-max-frequency = <1000000>; ++ }; ++ }; ++ ++ rp1_i2c0: i2c@70000 { ++ reg = <0xc0 0x40070000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c1: i2c@74000 { ++ reg = <0xc0 0x40074000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c2: i2c@78000 { ++ reg = <0xc0 0x40078000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c3: i2c@7c000 { ++ reg = <0xc0 0x4007c000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c4: i2c@80000 { ++ reg = <0xc0 0x40080000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c5: i2c@84000 { ++ reg = <0xc0 0x40084000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2c6: i2c@88000 { ++ reg = <0xc0 0x40088000 0x0 0x1000>; ++ compatible = "snps,designware-i2c"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS>; ++ i2c-scl-rising-time-ns = <65>; ++ i2c-scl-falling-time-ns = <100>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm0: pwm@98000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x40098000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM0>; ++ assigned-clock-rates = <50000000>; ++ status = "disabled"; ++ }; ++ ++ rp1_pwm1: pwm@9c000 { ++ compatible = "raspberrypi,rp1-pwm"; ++ reg = <0xc0 0x4009c000 0x0 0x100>; ++ #pwm-cells = <3>; ++ clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>; ++ assigned-clock-rates = <50000000>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s0: i2s@a0000 { ++ reg = <0xc0 0x400a0000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S0_TX>,<&rp1_dma RP1_DMA_I2S0_RX>; ++ dma-names = "tx", "rx"; ++ dma-maxburst = <4>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s1: i2s@a4000 { ++ reg = <0xc0 0x400a4000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ clock-names = "i2sclk"; ++ #sound-dai-cells = <0>; ++ dmas = <&rp1_dma RP1_DMA_I2S1_TX>,<&rp1_dma RP1_DMA_I2S1_RX>; ++ dma-names = "tx", "rx"; ++ dma-maxburst = <4>; ++ status = "disabled"; ++ }; ++ ++ rp1_i2s2: i2s@a8000 { ++ reg = <0xc0 0x400a8000 0x0 0x1000>; ++ compatible = "snps,designware-i2s"; ++ // Providing an interrupt disables DMA ++ // interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_I2S>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk0: sdio_clk0@b0004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b0004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_sdio_clk1: sdio_clk1@b4004 { ++ compatible = "raspberrypi,rp1-sdio-clk"; ++ reg = <0xc0 0x400b4004 0x0 0x1c>; ++ clocks = <&sdio_src &sdhci_core>; ++ clock-names = "src", "base"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_adc: adc@c8000 { ++ compatible = "raspberrypi,rp1-adc"; ++ reg = <0xc0 0x400c8000 0x0 0x4000>; ++ clocks = <&rp1_clocks RP1_CLK_ADC>; ++ clock-names = "adcclk"; ++ #clock-cells = <0>; ++ vref-supply = <&rp1_vdd_3v3>; ++ status = "disabled"; ++ }; ++ ++ rp1_gpio: gpio@d0000 { ++ reg = <0xc0 0x400d0000 0x0 0xc000>, ++ <0xc0 0x400e0000 0x0 0xc000>, ++ <0xc0 0x400f0000 0x0 0xc000>; ++ compatible = "raspberrypi,rp1-gpio"; ++ interrupts = , ++ , ++ ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&rp1_gpio 0 0 54>; ++ ++ rp1_uart0_14_15: rp1_uart0_14_15 { ++ pin_txd { ++ function = "uart0"; ++ pins = "gpio14"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart0"; ++ pins = "gpio15"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart0_ctsrts_16_17: rp1_uart0_ctsrts_16_17 { ++ pin_cts { ++ function = "uart0"; ++ pins = "gpio16"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart0"; ++ pins = "gpio17"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart1_0_1: rp1_uart1_0_1 { ++ pin_txd { ++ function = "uart1"; ++ pins = "gpio0"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart1"; ++ pins = "gpio1"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart1_ctsrts_2_3: rp1_uart1_ctsrts_2_3 { ++ pin_cts { ++ function = "uart1"; ++ pins = "gpio2"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart1"; ++ pins = "gpio3"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart2_4_5: rp1_uart2_4_5 { ++ pin_txd { ++ function = "uart2"; ++ pins = "gpio4"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart2"; ++ pins = "gpio5"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart2_ctsrts_6_7: rp1_uart2_ctsrts_6_7 { ++ pin_cts { ++ function = "uart2"; ++ pins = "gpio6"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart2"; ++ pins = "gpio7"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart3_8_9: rp1_uart3_8_9 { ++ pin_txd { ++ function = "uart3"; ++ pins = "gpio8"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart3"; ++ pins = "gpio9"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart3_ctsrts_10_11: rp1_uart3_ctsrts_10_11 { ++ pin_cts { ++ function = "uart3"; ++ pins = "gpio10"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart3"; ++ pins = "gpio11"; ++ bias-disable; ++ }; ++ }; ++ rp1_uart4_12_13: rp1_uart4_12_13 { ++ pin_txd { ++ function = "uart4"; ++ pins = "gpio12"; ++ bias-disable; ++ }; ++ pin_rxd { ++ function = "uart4"; ++ pins = "gpio13"; ++ bias-pull-up; ++ }; ++ }; ++ rp1_uart4_ctsrts_14_15: rp1_uart4_ctsrts_14_15 { ++ pin_cts { ++ function = "uart4"; ++ pins = "gpio14"; ++ bias-pull-up; ++ }; ++ pin_rts { ++ function = "uart4"; ++ pins = "gpio15"; ++ bias-disable; ++ }; ++ }; ++ ++ rp1_sdio0_22_27: rp1_sdio0_22_27 { ++ pin_clk { ++ function = "sd0"; ++ pins = "gpio22"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd0"; ++ pins = "gpio23"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd0"; ++ pins = "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_sdio1_28_33: rp1_sdio1_28_33 { ++ pin_clk { ++ function = "sd1"; ++ pins = "gpio28"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pin_cmd { ++ function = "sd1"; ++ pins = "gpio29"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ pins_dat { ++ function = "sd1"; ++ pins = "gpio30", "gpio31", "gpio32", "gpio33"; ++ bias-pull-up; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ rp1_i2s0_18_21: rp1_i2s0_18_21 { ++ function = "i2s0"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2s1_18_21: rp1_i2s1_18_21 { ++ function = "i2s1"; ++ pins = "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_i2c4_34_35: rp1_i2c4_34_35 { ++ function = "i2c4"; ++ pins = "gpio34", "gpio35"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c6_38_39: rp1_i2c6_38_39 { ++ function = "i2c6"; ++ pins = "gpio38", "gpio39"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c4_40_41: rp1_i2c4_40_41 { ++ function = "i2c4"; ++ pins = "gpio40", "gpio41"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c5_44_45: rp1_i2c5_44_45 { ++ function = "i2c5"; ++ pins = "gpio44", "gpio45"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c0_0_1: rp1_i2c0_0_1 { ++ function = "i2c0"; ++ pins = "gpio0", "gpio1"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c0_8_9: rp1_i2c0_8_9 { ++ function = "i2c0"; ++ pins = "gpio8", "gpio9"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c1_2_3: rp1_i2c1_2_3 { ++ function = "i2c1"; ++ pins = "gpio2", "gpio3"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c1_10_11: rp1_i2c1_10_11 { ++ function = "i2c1"; ++ pins = "gpio10", "gpio11"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c2_4_5: rp1_i2c2_4_5 { ++ function = "i2c2"; ++ pins = "gpio4", "gpio5"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c2_12_13: rp1_i2c2_12_13 { ++ function = "i2c2"; ++ pins = "gpio12", "gpio13"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_6_7: rp1_i2c3_6_7 { ++ function = "i2c3"; ++ pins = "gpio6", "gpio7"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_14_15: rp1_i2c3_14_15 { ++ function = "i2c3"; ++ pins = "gpio14", "gpio15"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ rp1_i2c3_22_23: rp1_i2c3_22_23 { ++ function = "i2c3"; ++ pins = "gpio22", "gpio23"; ++ drive-strength = <12>; ++ bias-pull-up; ++ }; ++ ++ // DPI mappings with HSYNC,VSYNC but without PIXCLK,DE ++ rp1_dpi_16bit_gpio2: rp1_dpi_16bit_gpio2 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio2: rp1_dpi_16bit_cpadhi_gpio2 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio2: rp1_dpi_16bit_pad666_gpio2 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio2: rp1_dpi_18bit_gpio2 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio2: rp1_dpi_18bit_cpadhi_gpio2 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio2: rp1_dpi_24bit_gpio2 { /* Mode 7 */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3", "gpio4", "gpio5", ++ "gpio6", "gpio7", "gpio8", "gpio9", ++ "gpio10", "gpio11", "gpio12", "gpio13", ++ "gpio14", "gpio15", "gpio16", "gpio17", ++ "gpio18", "gpio19", "gpio20", "gpio21", ++ "gpio22", "gpio23", "gpio24", "gpio25", ++ "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ rp1_dpi_hvsync: rp1_dpi_hvsync { /* Sync only, for use with int VDAC */ ++ function = "dpi"; ++ pins = "gpio2", "gpio3"; ++ bias-disable; ++ }; ++ ++ // More DPI mappings, including PIXCLK,DE on GPIOs 0,1 ++ rp1_dpi_16bit_gpio0: rp1_dpi_16bit_gpio0 { /* Mode 2, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_cpadhi_gpio0: rp1_dpi_16bit_cpadhi_gpio0 { /* Mode 3 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24"; ++ bias-disable; ++ }; ++ rp1_dpi_16bit_pad666_gpio0: rp1_dpi_16bit_pad666_gpio0 { /* Mode 4 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio5", "gpio6", "gpio7", "gpio8", ++ "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio21", "gpio22", "gpio23", "gpio24", ++ "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_gpio0: rp1_dpi_18bit_gpio0 { /* Mode 5, not fully supported by RP1 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21"; ++ bias-disable; ++ }; ++ rp1_dpi_18bit_cpadhi_gpio0: rp1_dpi_18bit_cpadhi_gpio0 { /* Mode 6 */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25"; ++ bias-disable; ++ }; ++ rp1_dpi_24bit_gpio0: rp1_dpi_24bit_gpio0 { /* Mode 7 -- All GPIOs used! */ ++ function = "dpi"; ++ pins = "gpio0", "gpio1", "gpio2", "gpio3", ++ "gpio4", "gpio5", "gpio6", "gpio7", ++ "gpio8", "gpio9", "gpio10", "gpio11", ++ "gpio12", "gpio13", "gpio14", "gpio15", ++ "gpio16", "gpio17", "gpio18", "gpio19", ++ "gpio20", "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25", "gpio26", "gpio27"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc0_gpio4: rp1_gpclksrc0_gpio4 { ++ function = "gpclk0"; ++ pins = "gpio4"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc0_gpio20: rp1_gpclksrc0_gpio20 { ++ function = "gpclk0"; ++ pins = "gpio20"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio5: rp1_gpclksrc1_gpio5 { ++ function = "gpclk1"; ++ pins = "gpio5"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio18: rp1_gpclksrc1_gpio18 { ++ function = "gpclk1"; ++ pins = "gpio18"; ++ bias-disable; ++ }; ++ ++ rp1_gpclksrc1_gpio21: rp1_gpclksrc1_gpio21 { ++ function = "gpclk1"; ++ pins = "gpio21"; ++ bias-disable; ++ }; ++ ++ rp1_pwm1_gpio45: rp1_pwm1_gpio45 { ++ function = "pwm1"; ++ pins = "gpio45"; ++ bias-pull-down; ++ }; ++ ++ rp1_spi0_gpio9: rp1_spi0_gpio9 { ++ function = "spi0"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi0_cs_gpio7: rp1_spi0_cs_gpio7 { ++ function = "spi0"; ++ pins = "gpio7", "gpio8"; ++ bias-pull-up; ++ }; ++ ++ rp1_spi1_gpio19: rp1_spi1_gpio19 { ++ function = "spi1"; ++ pins = "gpio19", "gpio20", "gpio21"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi2_gpio1: rp1_spi2_gpio1 { ++ function = "spi2"; ++ pins = "gpio1", "gpio2", "gpio3"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi3_gpio5: rp1_spi3_gpio5 { ++ function = "spi3"; ++ pins = "gpio5", "gpio6", "gpio7"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi4_gpio9: rp1_spi4_gpio9 { ++ function = "spi4"; ++ pins = "gpio9", "gpio10", "gpio11"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi5_gpio13: rp1_spi5_gpio13 { ++ function = "spi5"; ++ pins = "gpio13", "gpio14", "gpio15"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_gpio49: rp1_spi8_gpio49 { ++ function = "spi8"; ++ pins = "gpio49", "gpio50", "gpio51"; ++ bias-disable; ++ drive-strength = <12>; ++ slew-rate = <1>; ++ }; ++ ++ rp1_spi8_cs_gpio52: rp1_spi8_cs_gpio52 { ++ function = "spi0"; ++ pins = "gpio52", "gpio53"; ++ bias-pull-up; ++ }; ++ }; ++ ++ rp1_eth: ethernet@100000 { ++ reg = <0xc0 0x40100000 0x0 0x4000>; ++ compatible = "cdns,macb"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = ; ++ clocks = <&macb_pclk &macb_hclk &rp1_clocks RP1_CLK_ETH_TSU>; ++ clock-names = "pclk", "hclk", "tsu_clk"; ++ phy-mode = "rgmii-id"; ++ cdns,aw2w-max-pipe = /bits/ 8 <8>; ++ cdns,ar2r-max-pipe = /bits/ 8 <8>; ++ cdns,use-aw2b-fill; ++ local-mac-address = [00 00 00 00 00 00]; ++ status = "disabled"; ++ }; ++ ++ rp1_csi0: csi@110000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40110000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x40114000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40120000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x40124000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_csi1: csi@128000 { ++ compatible = "raspberrypi,rp1-cfe"; ++ reg = <0xc0 0x40128000 0x0 0x100>, // CSI2 DMA address ++ <0xc0 0x4012c000 0x0 0x100>, // PHY/CSI Host address ++ <0xc0 0x40138000 0x0 0x100>, // MIPI CFG address ++ <0xc0 0x4013c000 0x0 0x1000>; // PiSP FE address ++ ++ // interrupts must match rp1_pisp_fe setup ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clock-rates = <25000000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc0: mmc@180000 { ++ reg = <0xc0 0x40180000 0x0 0x100>; ++ compatible = "raspberrypi,rp1-dwcmshc"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk0>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ /* Bank 0 VDDIO is fixed */ ++ no-1-8-v; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_mmc1: mmc@184000 { ++ reg = <0xc0 0x40184000 0x0 0x100>; ++ compatible = "raspberrypi,rp1-dwcmshc"; ++ interrupts = ; ++ clocks = <&rp1_clocks RP1_CLK_SYS &sdhci_core ++ &rp1_clocks RP1_CLK_SDIO_TIMER ++ &rp1_sdio_clk1>; ++ clock-names = "bus", "core", "timeout", "sdio"; ++ bus-width = <4>; ++ vmmc-supply = <&rp1_vdd_3v3>; ++ /* Nerf SDR speeds */ ++ sdhci-caps-mask = <0x3 0x0>; ++ broken-cd; ++ status = "disabled"; ++ }; ++ ++ rp1_dma: dma@188000 { ++ reg = <0xc0 0x40188000 0x0 0x1000>; ++ compatible = "snps,axi-dma-1.01a"; ++ interrupts = ; ++ clocks = <&sdhci_core &rp1_clocks RP1_CLK_SYS>; ++ clock-names = "core-clk", "cfgr-clk"; ++ ++ #dma-cells = <1>; ++ dma-channels = <8>; ++ snps,dma-masters = <1>; ++ snps,dma-targets = <64>; ++ snps,data-width = <4>; // (8 << 4) == 128 bits ++ snps,block-size = <0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000 0x40000>; ++ snps,priority = <0 1 2 3 4 5 6 7>; ++ snps,axi-max-burst-len = <4>; ++ status = "disabled"; ++ }; ++ ++ rp1_usb0: usb@200000 { ++ reg = <0xc0 0x40200000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,parkmode-disable-ss-quirk; ++ snps,parkmode-disable-hs-quirk; ++ snps,parkmode-disable-fsls-quirk; ++ snps,tx-max-burst = /bits/ 8 <8>; ++ snps,tx-thr-num-pkt = /bits/ 8 <2>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ rp1_usb1: usb@300000 { ++ reg = <0xc0 0x40300000 0x0 0x100000>; ++ compatible = "snps,dwc3"; ++ dr_mode = "host"; ++ usb3-lpm-capable; ++ snps,axi-pipe-limit = /bits/ 8 <8>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,parkmode-disable-ss-quirk; ++ snps,parkmode-disable-hs-quirk; ++ snps,parkmode-disable-fsls-quirk; ++ snps,tx-max-burst = /bits/ 8 <8>; ++ snps,tx-thr-num-pkt = /bits/ 8 <2>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ rp1_dsi0: dsi@110000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40118000 0x0 0x1000>, // MIPI0 DSI DMA (ArgonDPI) ++ <0xc0 0x4011c000 0x0 0x1000>, // MIPI0 DSI Host (SNPS) ++ <0xc0 0x40120000 0x0 0x1000>; // MIPI0 CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI0_DPI>, ++ <&rp1_clocks RP1_CLK_MIPI0_DSI_BYTECLOCK>, ++ <&clk_xosc>, // hardwired to DSI "refclk" ++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI0_CFG>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ rp1_dsi1: dsi@128000 { ++ compatible = "raspberrypi,rp1dsi"; ++ status = "disabled"; ++ reg = <0xc0 0x40130000 0x0 0x1000>, // MIPI1 DSI DMA (ArgonDPI) ++ <0xc0 0x40134000 0x0 0x1000>, // MIPI1 DSI Host (SNPS) ++ <0xc0 0x40138000 0x0 0x1000>; // MIPI1 CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>, ++ <&rp1_clocks RP1_CLK_MIPI1_DPI>, ++ <&rp1_clocks RP1_CLK_MIPI1_DSI_BYTECLOCK>, ++ <&clk_xosc>, // hardwired to DSI "refclk" ++ <&rp1_clocks RP1_PLL_SYS>; // alternate parent for divide ++ clock-names = "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_MIPI1_CFG>; ++ assigned-clock-rates = <25000000>; ++ }; ++ ++ /* VEC and DPI both need to control PLL_VIDEO and cannot work together; */ ++ /* config.txt should enable one or other using dtparam=vec or an overlay. */ ++ rp1_vec: vec@144000 { ++ compatible = "raspberrypi,rp1vec"; ++ status = "disabled"; ++ reg = <0xc0 0x40144000 0x0 0x1000>, // VIDEO_OUT_VEC ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_VEC>; ++ ++ assigned-clocks = <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>, ++ <&rp1_clocks RP1_CLK_VEC>; ++ assigned-clock-rates = <1188000000>, ++ <108000000>, ++ <108000000>; ++ assigned-clock-parents = <0>, ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>, ++ <&rp1_clocks RP1_PLL_VIDEO_SEC>; ++ }; ++ ++ rp1_dpi: dpi@148000 { ++ compatible = "raspberrypi,rp1dpi"; ++ status = "disabled"; ++ reg = <0xc0 0x40148000 0x0 0x1000>, // VIDEO_OUT DPI ++ <0xc0 0x40140000 0x0 0x1000>; // VIDEO_OUT_CFG ++ ++ interrupts = ; ++ ++ clocks = <&rp1_clocks RP1_CLK_DPI>, // DPI pixel clock ++ <&rp1_clocks RP1_PLL_VIDEO>, // PLL primary divider, and ++ <&rp1_clocks RP1_PLL_VIDEO_CORE>; // VCO, which we also control ++ clock-names = "dpiclk", "plldiv", "pllcore"; ++ ++ assigned-clocks = <&rp1_clocks RP1_CLK_DPI>; ++ assigned-clock-parents = <&rp1_clocks RP1_PLL_VIDEO>; ++ }; ++ }; ++}; ++ ++&clocks { ++ clk_xosc: clk_xosc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "xosc"; ++ clock-frequency = <50000000>; ++ }; ++ macb_pclk: macb_pclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "pclk"; ++ clock-frequency = <200000000>; ++ }; ++ macb_hclk: macb_hclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "hclk"; ++ clock-frequency = <200000000>; ++ }; ++ sdio_src: sdio_src { ++ // 400 MHz on FPGA. PLL sys VCO on asic ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "src"; ++ clock-frequency = <1000000000>; ++ }; ++ sdhci_core: sdhci_core { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-output-names = "core"; ++ clock-frequency = <50000000>; ++ }; ++ /* GPIO derived clock sources. Each GPIO with a GPCLK function ++ * can drive its output from the respective GPCLK ++ * generator, and provide a clock source to other internal ++ * dividers. Add dummy sources here so that they can be overridden ++ * with overlays. ++ */ ++ clksrc_gp0: clksrc_gp0 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP0>; ++ clock-output-names = "clksrc_gp0"; ++ }; ++ clksrc_gp1: clksrc_gp1 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP1>; ++ clock-output-names = "clksrc_gp1"; ++ }; ++ clksrc_gp2: clksrc_gp2 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP2>; ++ clock-output-names = "clksrc_gp2"; ++ }; ++ clksrc_gp3: clksrc_gp3 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ clock-div = <1>; ++ clock-mult = <1>; ++ #clock-cells = <0>; ++ clocks = <&rp1_clocks RP1_CLK_GP3>; ++ clock-output-names = "clksrc_gp3"; ++ }; ++ clksrc_gp4: clksrc_gp4 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP4>; ++ clock-output-names = "clksrc_gp4"; ++ }; ++ clksrc_gp5: clksrc_gp5 { ++ status = "disabled"; ++ compatible = "fixed-factor-clock"; ++ #clock-cells = <0>; ++ clock-div = <1>; ++ clock-mult = <1>; ++ clocks = <&rp1_clocks RP1_CLK_GP5>; ++ clock-output-names = "clksrc_gp5"; ++ }; ++}; ++ ++/ { ++ rp1_vdd_3v3: rp1_vdd_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++}; diff --git a/arch/arm64/boot/dts/overlays b/arch/arm64/boot/dts/overlays new file mode 120000 index 000000000000..ded08646b6f6 @@ -58633,10 +60670,10 @@ index 000000000000..ded08646b6f6 \ No newline at end of file diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig new file mode 100644 -index 000000000000..38ef9d2d8221 +index 000000000000..8e6081631a41 --- /dev/null +++ b/arch/arm64/configs/bcm2711_defconfig -@@ -0,0 +1,1677 @@ +@@ -0,0 +1,1698 @@ +CONFIG_LOCALVERSION="-v8" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -58680,6 +60717,9 @@ index 000000000000..38ef9d2d8221 +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set ++CONFIG_HOTPLUG_CPU=y ++CONFIG_NUMA=y ++CONFIG_NUMA_EMULATION=y +CONFIG_COMPAT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y @@ -58714,7 +60754,6 @@ index 000000000000..38ef9d2d8221 +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -58742,7 +60781,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -58980,6 +61019,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -59101,11 +61141,14 @@ index 000000000000..38ef9d2d8221 +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_HWMON=y +CONFIG_EEPROM_AT24=m @@ -59125,6 +61168,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_SATA_MV=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -59137,6 +61181,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -59296,7 +61341,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -59370,6 +61415,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_MMIO=m +CONFIG_SPI_GPIO=m ++CONFIG_SPI_RP2040_GPIO_BRIDGE=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_PPS_CLIENT_LDISC=m @@ -59590,6 +61636,8 @@ index 000000000000..38ef9d2d8221 +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_MEDIA_PCI_SUPPORT=y ++CONFIG_MEDIA_PCI_HAILO=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m @@ -59623,6 +61671,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX500=m +CONFIG_VIDEO_IMX519=m +CONFIG_VIDEO_IMX708=m +CONFIG_VIDEO_MT9V011=m @@ -59716,6 +61765,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -59833,6 +61883,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -59865,6 +61916,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -59881,6 +61933,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -59892,6 +61945,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -59910,6 +61964,8 @@ index 000000000000..38ef9d2d8221 +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -60130,6 +62186,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_BRCMSTB=y ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_PWM_RP1=y @@ -60195,6 +62252,7 @@ index 000000000000..38ef9d2d8221 +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -60316,10 +62374,10 @@ index 000000000000..38ef9d2d8221 +# CONFIG_STRICT_DEVMEM is not set diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig new file mode 100644 -index 000000000000..67e9a9703528 +index 000000000000..7a4f1d4e151f --- /dev/null +++ b/arch/arm64/configs/bcm2712_defconfig -@@ -0,0 +1,1680 @@ +@@ -0,0 +1,1701 @@ +CONFIG_LOCALVERSION="-v8-16k" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -60364,6 +62422,9 @@ index 000000000000..67e9a9703528 +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +CONFIG_ARM64_16K_PAGES=y ++CONFIG_HOTPLUG_CPU=y ++CONFIG_NUMA=y ++CONFIG_NUMA_EMULATION=y +CONFIG_COMPAT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y @@ -60400,7 +62461,6 @@ index 000000000000..67e9a9703528 +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -60428,7 +62488,7 @@ index 000000000000..67e9a9703528 +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -60666,6 +62726,7 @@ index 000000000000..67e9a9703528 +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -60787,11 +62848,14 @@ index 000000000000..67e9a9703528 +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_HWMON=y +CONFIG_EEPROM_AT24=m @@ -60811,6 +62875,7 @@ index 000000000000..67e9a9703528 +CONFIG_SATA_MV=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -60823,6 +62888,7 @@ index 000000000000..67e9a9703528 +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -60982,7 +63048,7 @@ index 000000000000..67e9a9703528 +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -61056,6 +63122,7 @@ index 000000000000..67e9a9703528 +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_MMIO=m +CONFIG_SPI_GPIO=m ++CONFIG_SPI_RP2040_GPIO_BRIDGE=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SLAVE=y +CONFIG_PPS_CLIENT_LDISC=m @@ -61276,6 +63343,8 @@ index 000000000000..67e9a9703528 +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_MEDIA_PCI_SUPPORT=y ++CONFIG_MEDIA_PCI_HAILO=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m @@ -61309,6 +63378,7 @@ index 000000000000..67e9a9703528 +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX296=m +CONFIG_VIDEO_IMX477=m ++CONFIG_VIDEO_IMX500=m +CONFIG_VIDEO_IMX519=m +CONFIG_VIDEO_IMX708=m +CONFIG_VIDEO_MT9V011=m @@ -61402,6 +63472,7 @@ index 000000000000..67e9a9703528 +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -61519,6 +63590,7 @@ index 000000000000..67e9a9703528 +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -61551,6 +63623,7 @@ index 000000000000..67e9a9703528 +CONFIG_USB_DWC2=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -61567,6 +63640,7 @@ index 000000000000..67e9a9703528 +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -61578,6 +63652,7 @@ index 000000000000..67e9a9703528 +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -61596,6 +63671,8 @@ index 000000000000..67e9a9703528 +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -61816,6 +63893,7 @@ index 000000000000..67e9a9703528 +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m +CONFIG_PWM_BRCMSTB=y ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_PWM_RP1=y @@ -61881,6 +63959,7 @@ index 000000000000..67e9a9703528 +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -62002,10 +64081,10 @@ index 000000000000..67e9a9703528 +# CONFIG_STRICT_DEVMEM is not set diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig new file mode 100644 -index 000000000000..38ee19e19f46 +index 000000000000..86ad9e77c251 --- /dev/null +++ b/arch/arm64/configs/bcmrpi3_defconfig -@@ -0,0 +1,1561 @@ +@@ -0,0 +1,1575 @@ +CONFIG_LOCALVERSION="-v8" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y @@ -62078,7 +64157,6 @@ index 000000000000..38ee19e19f46 +CONFIG_MAC_PARTITION=y +CONFIG_BINFMT_MISC=y +CONFIG_ZSWAP=y -+CONFIG_Z3FOLD=m +# CONFIG_COMPAT_BRK is not set +CONFIG_CMA=y +CONFIG_LRU_GEN=y @@ -62105,7 +64183,7 @@ index 000000000000..38ee19e19f46 +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y -+CONFIG_NET_FOU=m ++CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m @@ -62340,6 +64418,7 @@ index 000000000000..38ee19e19f46 +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m ++CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_ATALK=m @@ -62450,11 +64529,14 @@ index 000000000000..38ee19e19f46 +CONFIG_MTD_UBI=m +CONFIG_OF_CONFIGFS=y +CONFIG_ZRAM=m ++CONFIG_ZRAM_WRITEBACK=y ++CONFIG_ZRAM_MULTI_COMP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_ATA_OVER_ETH=m ++CONFIG_BLK_DEV_RBD=m +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_TI_ST=m @@ -62470,6 +64552,7 @@ index 000000000000..38ee19e19f46 +CONFIG_ATA=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m ++CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m @@ -62481,6 +64564,7 @@ index 000000000000..38ee19e19f46 +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_DELAY=m ++CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m @@ -62626,7 +64710,7 @@ index 000000000000..38ee19e19f46 +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_FSIA6B=m -+CONFIG_JOYSTICK_RPISENSE=m ++CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m @@ -62993,6 +65077,7 @@ index 000000000000..38ee19e19f46 +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC=m +CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD=m ++CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m +CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD=m @@ -63108,6 +65193,7 @@ index 000000000000..38ee19e19f46 +CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y ++CONFIG_I2C_HID_OF=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=m @@ -63138,6 +65224,7 @@ index 000000000000..38ee19e19f46 +CONFIG_USB_DWC2_HOST=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m @@ -63154,6 +65241,7 @@ index 000000000000..38ee19e19f46 +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m ++CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m @@ -63165,6 +65253,7 @@ index 000000000000..38ee19e19f46 +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m @@ -63183,6 +65272,8 @@ index 000000000000..38ee19e19f46 +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_UPD78F0730=m ++CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m @@ -63397,6 +65488,7 @@ index 000000000000..38ee19e19f46 +CONFIG_MAX31856=m +CONFIG_PWM=y +CONFIG_PWM_BCM2835=m ++CONFIG_PWM_GPIO=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_RASPBERRYPI_POE=m +CONFIG_RPI_AXIPERF=m @@ -63460,6 +65552,7 @@ index 000000000000..38ee19e19f46 +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y @@ -63631,10 +65724,10 @@ index 467ac2f768ac..813ae2bbbd52 100644 asmlinkage void aesbs_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c -index fd0f291e215e..b843b686affd 100644 +index 87ac0b9c0b4f..fe108a850d4d 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c -@@ -539,9 +539,14 @@ static void __init register_insn_emulation(struct insn_emulation *insn) +@@ -542,9 +542,14 @@ static void __init register_insn_emulation(struct insn_emulation *insn) switch (insn->status) { case INSN_DEPRECATED: @@ -63650,7 +65743,7 @@ index fd0f291e215e..b843b686affd 100644 break; case INSN_OBSOLETE: diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c -index eecedf5b67fa..33ac8dfb30ca 100644 +index 7466b6066d87..2c5f88bb8764 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -17,6 +17,7 @@ @@ -63713,10 +65806,10 @@ index 068e5bb2661b..0465e6645537 100644 /* diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c -index 95cb22c083c8..d8cdca9144ba 100644 +index d82fd6902ea8..15cbdeb56f61 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c -@@ -269,9 +269,9 @@ static void __init request_standard_resources(void) +@@ -270,9 +270,9 @@ static void __init request_standard_resources(void) size_t res_size; kernel_code.start = __pa_symbol(_stext); @@ -63728,6 +65821,172 @@ index 95cb22c083c8..d8cdca9144ba 100644 insert_resource(&iomem_resource, &kernel_code); insert_resource(&iomem_resource, &kernel_data); +diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig +index 2b8fd6bb7da0..1f60cd4dd057 100644 +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -230,6 +230,13 @@ config GENERIC_ARCH_NUMA + Enable support for generic NUMA implementation. Currently, RISC-V + and ARM64 use it. + ++config GENERIC_ARCH_NUMA_EMULATION ++ bool ++ depends on GENERIC_ARCH_NUMA ++ help ++ Enable NUMA emulation. Note that NUMA emulation will only be used if ++ the machine has no NUMA node. ++ + config FW_DEVLINK_SYNC_STATE_TIMEOUT + bool "sync_state() behavior defaults to timeout instead of strict" + help +diff --git a/drivers/base/Makefile b/drivers/base/Makefile +index 3079bfe53d04..34fcf5bd7370 100644 +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -25,6 +25,7 @@ obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o + obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o + obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o + obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o ++obj-$(CONFIG_GENERIC_ARCH_NUMA_EMULATION) += numa_emulation.o + obj-$(CONFIG_ACPI) += physical_location.o + + obj-y += test/ +diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c +index 96281de7010d..8f801e555878 100644 +--- a/drivers/base/arch_numa.c ++++ b/drivers/base/arch_numa.c +@@ -15,6 +15,8 @@ + + #include + ++#include "numa_emulation.h" ++ + struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; + EXPORT_SYMBOL(node_data); + nodemask_t numa_nodes_parsed __initdata; +@@ -30,6 +32,8 @@ static __init int numa_parse_early_param(char *opt) + return -EINVAL; + if (str_has_prefix(opt, "off")) + numa_off = true; ++ if (str_has_prefix(opt, "fake=")) ++ return numa_emu_cmdline(opt + 5); + + return 0; + } +@@ -556,6 +560,8 @@ void __init arch_numa_init(void) + return; + if (acpi_disabled && !numa_init(of_numa_init)) + return; ++ if (!numa_init(numa_emu_init)) ++ return; + } + + numa_init(dummy_numa_init); +diff --git a/drivers/base/numa_emulation.c b/drivers/base/numa_emulation.c +new file mode 100644 +index 000000000000..48298955beae +--- /dev/null ++++ b/drivers/base/numa_emulation.c +@@ -0,0 +1,72 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Simple NUMA emulation. ++ * ++ * Copyright © 2024 Raspberry Pi Ltd ++ * ++ * Author: Maíra Canal ++ * Author: Tvrtko Ursulin ++ */ ++#include ++#include ++ ++#include "numa_emulation.h" ++ ++static unsigned int emu_nodes; ++ ++int __init numa_emu_cmdline(char *str) ++{ ++ int ret; ++ ++ ret = kstrtouint(str, 10, &emu_nodes); ++ if (ret) ++ return ret; ++ ++ if (emu_nodes > MAX_NUMNODES) { ++ pr_notice("numa=fake=%u too large, reducing to %u\n", ++ emu_nodes, MAX_NUMNODES); ++ emu_nodes = MAX_NUMNODES; ++ } ++ ++ return 0; ++} ++ ++int __init numa_emu_init(void) ++{ ++ phys_addr_t start, end; ++ unsigned long size; ++ unsigned int i; ++ int ret; ++ ++ if (!emu_nodes) ++ return -EINVAL; ++ ++ start = memblock_start_of_DRAM(); ++ end = memblock_end_of_DRAM() - 1; ++ ++ size = DIV_ROUND_DOWN_ULL(end - start + 1, emu_nodes); ++ size = PAGE_ALIGN_DOWN(size); ++ ++ for (i = 0; i < emu_nodes; i++) { ++ u64 s, e; ++ ++ s = start + i * size; ++ e = s + size - 1; ++ ++ if (i == (emu_nodes - 1) && e != end) ++ e = end; ++ ++ ret = cma_check_range(&s, &e); ++ if (ret) ++ return ret; ++ ++ pr_info("Faking a node at [mem %pap-%pap]\n", &s, &e); ++ ret = numa_add_memblk(i, s, e + 1); ++ if (ret) { ++ pr_err("Failed to add fake NUMA node %d!\n", i); ++ break; ++ } ++ } ++ ++ return ret; ++} +diff --git a/drivers/base/numa_emulation.h b/drivers/base/numa_emulation.h +new file mode 100644 +index 000000000000..62b38215a2f0 +--- /dev/null ++++ b/drivers/base/numa_emulation.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * NUMA emulation header ++ * ++ * Copyright © 2024 Raspberry Pi Ltd ++ */ ++ ++#ifdef CONFIG_GENERIC_ARCH_NUMA_EMULATION ++int numa_emu_cmdline(char *str); ++int __init numa_emu_init(void); ++#else ++static inline int numa_emu_cmdline(char *str) ++{ ++ return -EINVAL; ++} ++ ++static int __init numa_emu_init(void) ++{ ++ return -EOPNOTSUPP; ++} ++#endif /* CONFIG_NUMA_EMU */ diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 0a5445ac5e1b..3029004fa262 100644 --- a/drivers/bluetooth/btbcm.c @@ -63785,7 +66044,7 @@ index c0436881a533..0717d12f972a 100644 if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data[2] & 0x07); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 625af75833fc..96c3c37b7577 100644 +index ea7ace87a9df..601667c291c9 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -5,6 +5,8 @@ @@ -63797,7 +66056,7 @@ index 625af75833fc..96c3c37b7577 100644 source "drivers/tty/Kconfig" config TTY_PRINTK -@@ -422,4 +424,12 @@ config ADI +@@ -442,4 +444,12 @@ config ADI and SSM (Silicon Secured Memory). Intended consumers of this driver include crash and makedumpfile. @@ -63811,10 +66070,10 @@ index 625af75833fc..96c3c37b7577 100644 + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index c5f532e412f1..2ae16025a64b 100644 +index 109af71c5416..0af99e408e35 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile -@@ -44,3 +44,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o +@@ -46,3 +46,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o @@ -65127,7 +67386,7 @@ index 7c486989dd04..4ebc94573195 100644 To compile this driver as a module, choose M here: the module will be called iproc-rng200 diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c -index 4c08efe7f375..84c964b63324 100644 +index 57a80ec93bad..0a5cb28ffed5 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -13,6 +13,7 @@ @@ -65178,7 +67437,7 @@ index 4c08efe7f375..84c964b63324 100644 for (count = 0; count < num_words; count++) ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA); -@@ -105,8 +113,10 @@ static int bcm2835_rng_init(struct hwrng *rng) +@@ -107,8 +115,10 @@ static int bcm2835_rng_init(struct hwrng *rng) } /* set warm-up count & enable */ @@ -65623,10 +67882,10 @@ index 000000000000..8606f39a1434 +MODULE_DESCRIPTION("Driver for accessing GPIOs from userspace"); +MODULE_AUTHOR("Jonathan Bell "); diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c -index c5c3197ee29f..02700cb16f90 100644 +index 4bdad9e3667f..c6c9d5d714b2 100644 --- a/drivers/char/tpm/tpm_tis_spi_main.c +++ b/drivers/char/tpm/tpm_tis_spi_main.c -@@ -347,7 +347,11 @@ static struct spi_driver tpm_tis_spi_driver = { +@@ -348,7 +348,11 @@ static struct spi_driver tpm_tis_spi_driver = { .pm = &tpm_tis_pm, .of_match_table = of_match_ptr(of_tis_spi_match), .acpi_match_table = ACPI_PTR(acpi_tis_spi_match), @@ -66091,7 +68350,7 @@ index fb04734afc80..6b6f77ba0a79 100644 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver"); diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c -index 829406dc44a2..9b331f249a98 100644 +index 4d411408e4af..60d01131b12b 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -34,6 +34,7 @@ static char *rpi_firmware_clk_names[] = { @@ -67328,10 +69587,10 @@ index 000000000000..7412e24d34cf +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-rp1.c b/drivers/clk/clk-rp1.c new file mode 100644 -index 000000000000..b4964babf84a +index 000000000000..ae383588063a --- /dev/null +++ b/drivers/clk/clk-rp1.c -@@ -0,0 +1,2422 @@ +@@ -0,0 +1,2500 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Raspberry Pi Ltd. @@ -67728,6 +69987,11 @@ index 000000000000..b4964babf84a + unsigned long cached_rate; +}; + ++struct rp1_varsrc { ++ struct clk_hw hw; ++ struct rp1_clockman *clockman; ++ unsigned long rate; ++}; + +struct rp1_clk_change { + struct clk_hw *hw; @@ -68748,6 +71012,34 @@ index 000000000000..b4964babf84a + rp1_debugfs_regset(clockman, 0, regs, i, dentry); +} + ++static int rp1_varsrc_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw); ++ ++ /* ++ * "varsrc" exists purely to let clock dividers know the frequency ++ * of an externally-managed clock source (such as MIPI DSI byte-clock) ++ * which may change at run-time as a side-effect of some other driver. ++ */ ++ varsrc->rate = rate; ++ return 0; ++} ++ ++static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct rp1_varsrc *varsrc = container_of(hw, struct rp1_varsrc, hw); ++ ++ return varsrc->rate; ++} ++ ++static long rp1_varsrc_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return rate; ++} ++ +static const struct clk_ops rp1_pll_core_ops = { + .is_prepared = rp1_pll_core_is_on, + .prepare = rp1_pll_core_on, @@ -68798,6 +71090,12 @@ index 000000000000..b4964babf84a + .debug_init = rp1_clk_debug_init, +}; + ++static const struct clk_ops rp1_varsrc_ops = { ++ .set_rate = rp1_varsrc_set_rate, ++ .recalc_rate = rp1_varsrc_recalc_rate, ++ .round_rate = rp1_varsrc_round_rate, ++}; ++ +static bool rp1_clk_is_claimed(const char *name); + +static struct clk_hw *rp1_register_pll_core(struct rp1_clockman *clockman, @@ -68981,6 +71279,35 @@ index 000000000000..b4964babf84a + return &clock->hw; +} + ++static struct clk_hw *rp1_register_varsrc(struct rp1_clockman *clockman, ++ const void *data) ++{ ++ const char *name = *(char const * const *)data; ++ struct rp1_varsrc *clock; ++ struct clk_init_data init; ++ int ret; ++ ++ memset(&init, 0, sizeof(init)); ++ init.parent_names = &ref_clock; ++ init.num_parents = 1; ++ init.name = name; ++ init.flags = CLK_IGNORE_UNUSED; ++ init.ops = &rp1_varsrc_ops; ++ ++ clock = devm_kzalloc(clockman->dev, sizeof(*clock), GFP_KERNEL); ++ if (!clock) ++ return NULL; ++ ++ clock->clockman = clockman; ++ clock->hw.init = &init; ++ ++ ret = devm_clk_hw_register(clockman->dev, &clock->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &clock->hw; ++} ++ +struct rp1_clk_desc { + struct clk_hw *(*clk_register)(struct rp1_clockman *clockman, + const void *data); @@ -69010,6 +71337,8 @@ index 000000000000..b4964babf84a + &(struct rp1_clock_data) \ + {__VA_ARGS__}) + ++#define REGISTER_VARSRC(n) _REGISTER(&rp1_register_varsrc, &(const char *){n}) ++ +static const struct rp1_clk_desc clk_desc_array[] = { + [RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE( + .name = "pll_sys_core", @@ -69652,6 +71981,9 @@ index 000000000000..b4964babf84a + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(3, 6), + ), ++ ++ [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi0_dsi_byteclk"), ++ [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC("clksrc_mipi1_dsi_byteclk"), +}; + +static bool rp1_clk_claimed[ARRAY_SIZE(clk_desc_array)]; @@ -69715,6 +72047,11 @@ index 000000000000..b4964babf84a + desc = &clk_desc_array[i]; + if (desc->clk_register && desc->data) { + hws[i] = desc->clk_register(clockman, desc->data); ++ if (IS_ERR_OR_NULL(hws[i])) { ++ pr_err("Failed to register RP1 clock '%s' (%ld) - wrong dtbs?\n", *(char **)desc->data, PTR_ERR(hws[i])); ++ hws[i] = NULL; ++ continue; ++ } + if (!strcmp(clk_hw_get_name(hws[i]), "clk_i2s")) { + clk_i2s = hws[i]; + clk_xosc = clk_hw_get_parent_by_index(clk_i2s, 0); @@ -69754,8 +72091,43 @@ index 000000000000..b4964babf84a +MODULE_AUTHOR("Naushir Patuck "); +MODULE_DESCRIPTION("RP1 clock driver"); +MODULE_LICENSE("GPL"); +diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c +index 9076d47ed2ef..9dc5dfeaca2a 100644 +--- a/drivers/dma-buf/heaps/system_heap.c ++++ b/drivers/dma-buf/heaps/system_heap.c +@@ -54,6 +54,11 @@ static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP}; + static const unsigned int orders[] = {8, 4, 0}; + #define NUM_ORDERS ARRAY_SIZE(orders) + ++static unsigned int module_max_order = orders[0]; ++ ++module_param_named(max_order, module_max_order, uint, 0400); ++MODULE_PARM_DESC(max_order, "Maximum allocation order override."); ++ + static struct sg_table *dup_sg_table(struct sg_table *table) + { + struct sg_table *new_table; +@@ -339,7 +344,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap, + struct system_heap_buffer *buffer; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + unsigned long size_remaining = len; +- unsigned int max_order = orders[0]; ++ unsigned int max_order = module_max_order; + struct dma_buf *dmabuf; + struct sg_table *table; + struct scatterlist *sg; +@@ -433,6 +438,9 @@ static int system_heap_create(void) + if (IS_ERR(sys_heap)) + return PTR_ERR(sys_heap); + ++ if (module_max_order > orders[0]) ++ module_max_order = orders[0]; ++ + return 0; + } + module_init(system_heap_create); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig -index 7a618f629e86..60b10aed1b81 100644 +index e36506471a4f..e8e029bab078 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -669,6 +669,10 @@ config UNIPHIER_XDMAC @@ -71184,7 +73556,7 @@ index 0807fb9eb262..e159f976a6b1 100644 MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c -index dd02f84e404d..43053530aa0b 100644 +index 72fb40de58b3..cc842d8ed2ad 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -12,6 +12,7 @@ @@ -71233,16 +73605,31 @@ index dd02f84e404d..43053530aa0b 100644 for (i = 0; i < chip->dw->hdata->nr_channels; i++) { axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL); axi_chan_disable(&chip->dw->chan[i]); -@@ -282,7 +305,7 @@ static struct axi_dma_lli *axi_desc_get(struct axi_dma_chan *chan, - static void axi_desc_put(struct axi_dma_desc *desc) - { - struct axi_dma_chan *chan = desc->chan; -- int count = atomic_read(&chan->descs_allocated); -+ u32 count = desc->hw_desc_count; - struct axi_dma_hw_desc *hw_desc; - int descs_put; +@@ -238,6 +261,15 @@ static u32 axi_chan_get_xfer_width(struct axi_dma_chan *chan, dma_addr_t src, + return __ffs(src | dst | len | BIT(max_width)); + } -@@ -304,6 +327,48 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc) ++static u32 axi_dma_encode_msize(u32 max_burst) ++{ ++ if (max_burst <= 1) ++ return DWAXIDMAC_BURST_TRANS_LEN_1; ++ if (max_burst > 1024) ++ return DWAXIDMAC_BURST_TRANS_LEN_1024; ++ return fls(max_burst) - 2; ++} ++ + static inline const char *axi_chan_name(struct axi_dma_chan *chan) + { + return dma_chan_name(&chan->vc.chan); +@@ -256,7 +288,6 @@ static struct axi_dma_desc *axi_desc_alloc(u32 num) + kfree(desc); + return NULL; + } +- desc->nr_hw_descs = num; + + return desc; + } +@@ -305,6 +336,48 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc) axi_desc_put(vd_to_axi_desc(vdesc)); } @@ -71291,7 +73678,7 @@ index dd02f84e404d..43053530aa0b 100644 static enum dma_status dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, struct dma_tx_state *txstate) -@@ -313,10 +378,7 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, +@@ -314,10 +387,7 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, enum dma_status status; u32 completed_length; unsigned long flags; @@ -71302,7 +73689,7 @@ index dd02f84e404d..43053530aa0b 100644 status = dma_cookie_status(dchan, cookie, txstate); if (status == DMA_COMPLETE || !txstate) -@@ -325,16 +387,31 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, +@@ -326,16 +396,31 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, spin_lock_irqsave(&chan->vc.lock, flags); vdesc = vchan_find_desc(&chan->vc, cookie); @@ -71341,7 +73728,7 @@ index dd02f84e404d..43053530aa0b 100644 return status; } -@@ -388,8 +465,6 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, +@@ -389,8 +474,6 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, return; } @@ -71350,7 +73737,7 @@ index dd02f84e404d..43053530aa0b 100644 config.dst_multblk_type = DWAXIDMAC_MBLK_TYPE_LL; config.src_multblk_type = DWAXIDMAC_MBLK_TYPE_LL; config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC; -@@ -522,7 +597,7 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) +@@ -523,7 +606,7 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) unsigned long reg_value, val; if (!chip->apb_regs) { @@ -71359,35 +73746,54 @@ index dd02f84e404d..43053530aa0b 100644 return; } -@@ -626,18 +701,25 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, +@@ -611,34 +694,41 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, + size_t axi_block_ts; + size_t block_ts; + u32 ctllo, ctlhi; +- u32 burst_len; ++ u32 burst_len = 0, mem_burst_msize, reg_burst_msize; + + axi_block_ts = chan->chip->dw->hdata->block_size[chan->id]; + + mem_width = __ffs(data_width | mem_addr | len); +- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32) +- mem_width = DWAXIDMAC_TRANS_WIDTH_32; + + if (!IS_ALIGNED(mem_addr, 4)) { + dev_err(chan->chip->dev, "invalid buffer alignment\n"); + return -EINVAL; + } + ++ /* Use a reasonable upper limit otherwise residue reporting granularity grows large */ ++ mem_burst_msize = axi_dma_encode_msize(16); ++ switch (chan->direction) { case DMA_MEM_TO_DEV: ++ reg_burst_msize = axi_dma_encode_msize(chan->config.dst_maxburst); reg_width = __ffs(chan->config.dst_addr_width); - device_addr = chan->config.dst_addr; + device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr); ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS | mem_width << CH_CTL_L_SRC_WIDTH_POS | -+ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS | -+ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS | ++ reg_burst_msize << CH_CTL_L_DST_MSIZE_POS | ++ mem_burst_msize << CH_CTL_L_SRC_MSIZE_POS | DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS | DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS; block_ts = len >> mem_width; break; case DMA_DEV_TO_MEM: ++ reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst); reg_width = __ffs(chan->config.src_addr_width); - device_addr = chan->config.src_addr; -+ /* Prevent partial access units getting lost */ -+ if (mem_width > reg_width) -+ mem_width = reg_width; + device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr); ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS | mem_width << CH_CTL_L_DST_WIDTH_POS | -+ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | -+ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS | ++ mem_burst_msize << CH_CTL_L_DST_MSIZE_POS | ++ reg_burst_msize << CH_CTL_L_SRC_MSIZE_POS | DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS; block_ts = len >> reg_width; -@@ -673,9 +755,6 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, +@@ -674,14 +764,17 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, } hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1); @@ -71397,16 +73803,37 @@ index dd02f84e404d..43053530aa0b 100644 hw_desc->lli->ctl_lo = cpu_to_le32(ctllo); set_desc_src_master(hw_desc); -@@ -770,6 +849,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr, + + hw_desc->len = len; ++ ++ if (burst_len && (chan->config.src_maxburst > burst_len)) ++ dev_warn_ratelimited(chan2dev(chan), ++ "%s: requested source burst length %u exceeds supported burst length %u - data may be lost\n", ++ axi_chan_name(chan), chan->config.src_maxburst, burst_len); ++ + return 0; + } + +@@ -698,9 +791,6 @@ static size_t calculate_block_len(struct axi_dma_chan *chan, + case DMA_MEM_TO_DEV: + data_width = BIT(chan->chip->dw->hdata->m_data_width); + mem_width = __ffs(data_width | dma_addr | buf_len); +- if (mem_width > DWAXIDMAC_TRANS_WIDTH_32) +- mem_width = DWAXIDMAC_TRANS_WIDTH_32; +- + block_len = axi_block_ts << mem_width; + break; + case DMA_DEV_TO_MEM: +@@ -771,6 +861,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr, src_addr += segment_len; } -+ desc->hw_desc_count = total_segments; ++ desc->nr_hw_descs = total_segments; + llp = desc->hw_desc[0].llp; /* Managed transfer list */ -@@ -835,6 +916,9 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, +@@ -836,6 +928,9 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, mem = sg_dma_address(sg); len = sg_dma_len(sg); num_segments = DIV_ROUND_UP(sg_dma_len(sg), axi_block_len); @@ -71416,34 +73843,34 @@ index dd02f84e404d..43053530aa0b 100644 segment_len = DIV_ROUND_UP(sg_dma_len(sg), num_segments); do { -@@ -849,6 +933,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, +@@ -850,6 +945,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, } while (len >= segment_len); } -+ desc->hw_desc_count = loop; ++ desc->nr_hw_descs = loop; + /* Set end-of-link to the last link descriptor of list */ set_desc_last(&desc->hw_desc[num_sgs - 1]); -@@ -956,6 +1042,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr, +@@ -957,6 +1054,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr, num++; } -+ desc->hw_desc_count = num; ++ desc->nr_hw_descs = num; + /* Set end-of-link to the last link descriptor of list */ set_desc_last(&desc->hw_desc[num - 1]); /* Managed transfer list */ -@@ -1004,7 +1092,7 @@ static void axi_chan_dump_lli(struct axi_dma_chan *chan, +@@ -1005,7 +1104,7 @@ static void axi_chan_dump_lli(struct axi_dma_chan *chan, static void axi_chan_list_dump_lli(struct axi_dma_chan *chan, struct axi_dma_desc *desc_head) { - int count = atomic_read(&chan->descs_allocated); -+ u32 count = desc_head->hw_desc_count; ++ int count = desc_head->nr_hw_descs; int i; for (i = 0; i < count; i++) -@@ -1047,11 +1135,11 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) +@@ -1048,11 +1147,11 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) { @@ -71452,19 +73879,29 @@ index dd02f84e404d..43053530aa0b 100644 struct axi_dma_desc *desc; struct virt_dma_desc *vd; unsigned long flags; -+ u32 count; ++ int count; u64 llp; int i; -@@ -1073,6 +1161,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) +@@ -1074,6 +1173,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) if (chan->cyclic) { desc = vd_to_axi_desc(vd); if (desc) { -+ count = desc->hw_desc_count; ++ count = desc->nr_hw_descs; llp = lo_hi_readq(chan->chan_regs + CH_LLP); for (i = 0; i < count; i++) { hw_desc = &desc->hw_desc[i]; -@@ -1325,6 +1414,10 @@ static int parse_device_properties(struct axi_dma_chip *chip) +@@ -1094,6 +1194,9 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) + /* Remove the completed descriptor from issued list before completing */ + list_del(&vd->node); + vchan_cookie_complete(vd); ++ ++ /* Submit queued descriptors after processing the completed ones */ ++ axi_chan_start_first_queued(chan); + } + + out: +@@ -1323,6 +1426,10 @@ static int parse_device_properties(struct axi_dma_chip *chip) chip->dw->hdata->nr_masters = tmp; @@ -71475,20 +73912,39 @@ index dd02f84e404d..43053530aa0b 100644 ret = device_property_read_u32(dev, "snps,data-width", &tmp); if (ret) return ret; -diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h -index eb267cb24f67..47c3a4f0dac3 100644 ---- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h -+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h -@@ -101,6 +101,7 @@ struct axi_dma_desc { +@@ -1375,6 +1482,7 @@ static int dw_probe(struct platform_device *pdev) + struct dw_axi_dma *dw; + struct dw_axi_dma_hcfg *hdata; + struct reset_control *resets; ++ unsigned int max_seg_size; + unsigned int flags; + u32 i; + int ret; +@@ -1490,9 +1598,21 @@ static int dw_probe(struct platform_device *pdev) + * Synopsis DesignWare AxiDMA datasheet mentioned Maximum + * supported blocks is 1024. Device register width is 4 bytes. + * Therefore, set constraint to 1024 * 4. ++ * However, if all channels specify a greater value, use that instead. + */ ++ + dw->dma.dev->dma_parms = &dw->dma_parms; +- dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE); ++ max_seg_size = UINT_MAX; ++ for (i = 0; i < dw->hdata->nr_channels; i++) { ++ unsigned int block_size = chip->dw->hdata->block_size[i]; ++ ++ if (!block_size) ++ block_size = MAX_BLOCK_SIZE; ++ max_seg_size = min(block_size, max_seg_size); ++ } ++ ++ dma_set_max_seg_size(&pdev->dev, max_seg_size); ++ + platform_set_drvdata(pdev, chip); - struct virt_dma_desc vd; - struct axi_dma_chan *chan; -+ u32 hw_desc_count; - u32 completed_blocks; - u32 length; - u32 period_len; + pm_runtime_enable(chip->dev); diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c -index d9629ff87861..e2ffd734d5e8 100644 +index 2328ca58bba6..7a1e42237cf2 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -315,7 +315,14 @@ static int psci_sys_reset(struct notifier_block *nb, unsigned long action, @@ -71508,10 +73964,10 @@ index d9629ff87861..e2ffd734d5e8 100644 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); } diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c -index f66efaa5196d..17abde1e7d55 100644 +index 428ae54d3196..f1a2505ebc9e 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c -@@ -13,6 +13,7 @@ +@@ -14,6 +14,7 @@ #include #include #include @@ -71519,7 +73975,7 @@ index f66efaa5196d..17abde1e7d55 100644 #include #include -@@ -31,8 +32,11 @@ struct rpi_firmware { +@@ -32,8 +33,11 @@ struct rpi_firmware { u32 enabled; struct kref consumers; @@ -71531,7 +73987,7 @@ index f66efaa5196d..17abde1e7d55 100644 static DEFINE_MUTEX(transaction_lock); static void response_callback(struct mbox_client *cl, void *msg) -@@ -174,15 +178,92 @@ int rpi_firmware_property(struct rpi_firmware *fw, +@@ -175,15 +179,92 @@ int rpi_firmware_property(struct rpi_firmware *fw, kfree(data); @@ -71624,7 +74080,7 @@ index f66efaa5196d..17abde1e7d55 100644 int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_REVISION, &packet, sizeof(packet)); -@@ -192,7 +273,35 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) +@@ -193,7 +274,35 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) /* This is not compatible with y2038 */ date_and_time = packet; @@ -71661,7 +74117,7 @@ index f66efaa5196d..17abde1e7d55 100644 } static void -@@ -207,6 +316,11 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) +@@ -208,6 +317,11 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon", -1, NULL, 0); @@ -71673,7 +74129,7 @@ index f66efaa5196d..17abde1e7d55 100644 } static void rpi_register_clk_driver(struct device *dev) -@@ -299,8 +413,10 @@ static int rpi_firmware_probe(struct platform_device *pdev) +@@ -300,8 +414,10 @@ static int rpi_firmware_probe(struct platform_device *pdev) kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -71684,7 +74140,7 @@ index f66efaa5196d..17abde1e7d55 100644 rpi_register_hwmon_driver(dev, fw); rpi_register_clk_driver(dev); -@@ -327,6 +443,7 @@ static int rpi_firmware_remove(struct platform_device *pdev) +@@ -328,6 +444,7 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_clk = NULL; rpi_firmware_put(fw); @@ -71692,7 +74148,7 @@ index f66efaa5196d..17abde1e7d55 100644 return 0; } -@@ -407,7 +524,35 @@ static struct platform_driver rpi_firmware_driver = { +@@ -408,7 +525,35 @@ static struct platform_driver rpi_firmware_driver = { .shutdown = rpi_firmware_shutdown, .remove = rpi_firmware_remove, }; @@ -71730,7 +74186,7 @@ index f66efaa5196d..17abde1e7d55 100644 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig -index e52e8b5ae88e..7e646ea60873 100644 +index 509f42e6ab6a..0c1e188c75a4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -207,10 +207,16 @@ config GPIO_BCM_XGS_IPROC @@ -73388,7 +75844,7 @@ index 000000000000..ad8cbd894ca6 +MODULE_DESCRIPTION("GPIO FSM driver"); +MODULE_ALIAS("platform:gpio-fsm"); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c -index 74fdf0d87b2c..7e26fa957d5e 100644 +index c9f9f4e36c89..25c08cc5cd20 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -234,6 +234,25 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -73565,10 +76021,10 @@ index 74fdf0d87b2c..7e26fa957d5e 100644 } else { if (flags & BGPIOF_NO_OUTPUT) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c -index bdd50a78e414..52923f616222 100644 +index ce9a94e33280..11bdd678272d 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c -@@ -1345,6 +1345,7 @@ static const struct of_device_id pca953x_dt_ids[] = { +@@ -1347,6 +1347,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, { .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), }, { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), }, @@ -73578,7 +76034,7 @@ index bdd50a78e414..52923f616222 100644 { .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), }, diff --git a/drivers/gpio/gpio-pwm.c b/drivers/gpio/gpio-pwm.c new file mode 100644 -index 000000000000..4a718b365a6f +index 000000000000..1dbdf8717eb3 --- /dev/null +++ b/drivers/gpio/gpio-pwm.c @@ -0,0 +1,144 @@ @@ -73618,7 +76074,7 @@ index 000000000000..4a718b365a6f + + pwm_get_state(pwm_gpio->pwm[off], &state); + state.duty_cycle = val ? state.period : 0; -+ pwm_apply_state(pwm_gpio->pwm[off], &state); ++ pwm_apply_might_sleep(pwm_gpio->pwm[off], &state); +} + +static int pwm_gpio_parse_dt(struct pwm_gpio *pwm_gpio, @@ -73663,7 +76119,7 @@ index 000000000000..4a718b365a6f + pwm_init_state(pwm_gpio->pwm[i], &state); + + state.duty_cycle = 0; -+ pwm_apply_state(pwm_gpio->pwm[i], &state); ++ pwm_apply_might_sleep(pwm_gpio->pwm[i], &state); + } + + pwm_gpio->gc.ngpio = num_gpios; @@ -73727,10 +76183,10 @@ index 000000000000..4a718b365a6f +MODULE_AUTHOR("Dave Stevenson "); +MODULE_DESCRIPTION("PWM GPIO driver"); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index 1c512ed3fa6d..d15870f7cbc0 100644 +index 5c0016c77d2a..3710585e7da4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c -@@ -57,6 +57,8 @@ +@@ -58,6 +58,8 @@ #define extra_checks 0 #endif @@ -73739,7 +76195,41 @@ index 1c512ed3fa6d..d15870f7cbc0 100644 /* Device and char device-related information */ static DEFINE_IDA(gpio_ida); static dev_t gpio_devt; -@@ -2591,8 +2593,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) +@@ -109,6 +111,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc); + static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc); + + static bool gpiolib_initialized; ++static int first_dynamic_gpiochip_num = -1; + + static inline void desc_set_label(struct gpio_desc *d, const char *label) + { +@@ -744,6 +747,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, + unsigned int i; + int base = 0; + int ret = 0; ++ int id; + + /* + * First: allocate and populate the internal stat container, and +@@ -768,7 +772,16 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, + else if (gc->parent) + device_set_node(&gdev->dev, dev_fwnode(gc->parent)); + +- gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL); ++ if (first_dynamic_gpiochip_num < 0) { ++ id = of_alias_get_highest_id("gpiochip"); ++ first_dynamic_gpiochip_num = (id >= 0) ? (id + 1) : 0; ++ } ++ ++ id = of_alias_get_id(gdev->dev.of_node, "gpiochip"); ++ if (id < 0) ++ id = first_dynamic_gpiochip_num; ++ ++ gdev->id = ida_alloc_range(&gpio_ida, id, ~0, GFP_KERNEL); + if (gdev->id < 0) { + ret = gdev->id; + goto err_free_gdev; +@@ -2592,8 +2605,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) value = !!value; /* GPIOs used for enabled IRQs shall not be set as output */ @@ -73750,7 +76240,7 @@ index 1c512ed3fa6d..d15870f7cbc0 100644 gpiod_err(desc, "%s: tried to set a GPIO tied to an IRQ as output\n", __func__); -@@ -3470,8 +3472,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) +@@ -3471,8 +3484,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) } /* To be valid for IRQ the line needs to be input or open drain */ @@ -73762,7 +76252,7 @@ index 1c512ed3fa6d..d15870f7cbc0 100644 "%s: tried to flag a GPIO set as output for IRQ\n", __func__); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index d1cad875d2f7..89eb6afe2688 100644 +index a5b92adb8aff..5352376b5c45 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -346,6 +346,8 @@ source "drivers/gpu/drm/v3d/Kconfig" @@ -73775,14 +76265,16 @@ index d1cad875d2f7..89eb6afe2688 100644 source "drivers/gpu/drm/etnaviv/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index a670c0d95023..0df4a7d4f8e2 100644 +index b120267fbe40..97b0c9bd6cd4 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile -@@ -199,3 +199,4 @@ obj-y += solomon/ +@@ -198,5 +198,6 @@ obj-$(CONFIG_DRM_HYPERV) += hyperv/ + obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-$(CONFIG_DRM_LOONGSON) += loongson/ - obj-$(CONFIG_DRM_PHYTIUM) += phytium/ +obj-y += rp1/ + obj-$(CONFIG_DRM_PHYTIUM) += phytium/ + obj-$(CONFIG_HYDCU_FIXUP_HEADER) += hygon/hydcu-fixup-header/ diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 3e6a4e2044c0..b1c5ef817598 100644 --- a/drivers/gpu/drm/bridge/Kconfig @@ -73795,6 +76287,30 @@ index 3e6a4e2044c0..b1c5ef817598 100644 help Driver for display connectors with support for DDC and hot-plug detection. Most display controllers handle display connectors +diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c +index a1dd2ead8dcc..307b6bd6a6d8 100644 +--- a/drivers/gpu/drm/bridge/panel.c ++++ b/drivers/gpu/drm/bridge/panel.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + struct panel_bridge { + struct drm_bridge bridge; +@@ -86,6 +87,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge, + drm_connector_attach_encoder(&panel_bridge->connector, + bridge->encoder); + ++#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) ++ backlight_set_display_name(panel_bridge->panel->backlight, ++ panel_bridge->connector.name); ++#endif ++ + if (bridge->dev->registered) { + if (connector->funcs->reset) + connector->funcs->reset(connector); diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c index 46198af9eebb..3f6db0f66812 100644 --- a/drivers/gpu/drm/bridge/tc358762.c @@ -73929,7 +76445,7 @@ index 784e63d70a42..d7c761d9fb72 100644 if (!drm_object_property_get_default_value(&plane->base, plane->zpos_property, diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c -index 98d3b10c08ae..1e7c35b36a39 100644 +index ab03b08433f8..3c5375016d73 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -580,6 +580,10 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, @@ -73992,6 +76508,38 @@ index 98d3b10c08ae..1e7c35b36a39 100644 return 0; } +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index 62d8a291c49c..2ae6ac3a4b7a 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -657,6 +657,13 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge, + * bridge will be called before the previous one to reverse the @pre_enable + * calling direction. + * ++ * Example: ++ * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E ++ * ++ * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting ++ * @post_disable order would be, ++ * Bridge B, Bridge A, Bridge E, Bridge D, Bridge C. ++ * + * Note: the bridge passed should be the one closest to the encoder + */ + void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, +@@ -753,6 +760,13 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge, + * If a bridge sets @pre_enable_prev_first, then the pre_enable for the + * prev bridge will be called before pre_enable of this bridge. + * ++ * Example: ++ * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E ++ * ++ * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting ++ * @pre_enable order would be, ++ * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B. ++ * + * Note: the bridge passed should be the one closest to the encoder + */ + void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index d021497841b8..973c6aeff8a1 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c @@ -74051,7 +76599,7 @@ index d021497841b8..973c6aeff8a1 100644 * drm_color_lut_check - check validity of lookup table * @lut: property blob containing LUT to check diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c -index c44d5bcf1284..fa125167c018 100644 +index 309aad5f0c80..476ea750acf4 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -33,6 +33,7 @@ @@ -74195,10 +76743,10 @@ index c44d5bcf1284..fa125167c018 100644 return drm_connector_set_panel_orientation(connector, orientation); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c -index d612133e2cf7..7d4ed1530ac2 100644 +index 618b04523033..e6698f3a5b73 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c -@@ -1837,7 +1837,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) +@@ -1851,7 +1851,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) struct drm_device *dev = fb_helper->dev; struct fb_info *info; unsigned int width, height; @@ -74207,7 +76755,7 @@ index d612133e2cf7..7d4ed1530ac2 100644 width = dev->mode_config.max_width; height = dev->mode_config.max_height; -@@ -1868,6 +1868,15 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) +@@ -1879,6 +1879,15 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) * register the fbdev emulation instance in kernel_fb_helper_list. */ mutex_unlock(&fb_helper->lock); @@ -74262,37 +76810,6 @@ index c90afb5d0898..49816a7353bc 100644 uint64_t default_mode; if (drm_object_property_get_default_value(&connector->base, -diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c -index 2e8f17c04522..ff9b9918b0a1 100644 ---- a/drivers/gpu/drm/i915/display/intel_backlight.c -+++ b/drivers/gpu/drm/i915/display/intel_backlight.c -@@ -274,7 +274,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, - struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; - - pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); -- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); - } - - static void -@@ -427,7 +427,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn - intel_backlight_set_pwm_level(old_conn_state, level); - - panel->backlight.pwm_state.enabled = false; -- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); - } - - void intel_backlight_disable(const struct drm_connector_state *old_conn_state) -@@ -749,7 +749,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, - - pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); - panel->backlight.pwm_state.enabled = true; -- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); -+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); - } - - static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1a59fca40252..0e941ce3d5a4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c @@ -74331,7 +76848,7 @@ index 9c45d641b521..5c8e5611304f 100644 * Start timer if we don't already have an update pending * on this crtc: diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig -index 869e535faefa..d3109ea534fe 100644 +index 3a2f4a9f1d46..307dd2c0fae4 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -194,6 +194,17 @@ config DRM_PANEL_ILITEK_ILI9341 @@ -74905,7 +77422,7 @@ index 000000000000..80e5bbe7a041 +MODULE_DESCRIPTION("ili9806 LCD panel driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c -index 7838947a1bf3..971f8ee56308 100644 +index bb201f848ae9..a77ce9f7db9d 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1,6 +1,9 @@ @@ -74918,15 +77435,27 @@ index 7838947a1bf3..971f8ee56308 100644 */ #include -@@ -42,6 +45,7 @@ struct ili9881c_desc { +@@ -37,11 +40,19 @@ struct ili9881c_instr { + } arg; + }; + ++enum ili9881_desc_flags { ++ ILI9881_FLAGS_NO_SHUTDOWN_CMDS = BIT(0), ++ ILI9881_FLAGS_PANEL_ON_IN_PREPARE = BIT(1), ++ ILI9881_FLAGS_MAX = BIT(31), ++}; ++ + struct ili9881c_desc { + const struct ili9881c_instr *init; const size_t init_length; const struct drm_display_mode *mode; const unsigned long mode_flags; + unsigned int lanes; ++ enum ili9881_desc_flags flags; }; struct ili9881c { -@@ -455,6 +459,228 @@ static const struct ili9881c_instr k101_im2byl02_init[] = { +@@ -455,6 +466,228 @@ static const struct ili9881c_instr k101_im2byl02_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; @@ -75155,7 +77684,7 @@ index 7838947a1bf3..971f8ee56308 100644 static const struct ili9881c_instr tl050hdv35_init[] = { ILI9881C_SWITCH_PAGE_INSTR(3), ILI9881C_COMMAND_INSTR(0x01, 0x00), -@@ -830,17 +1056,604 @@ static const struct ili9881c_instr w552946ab_init[] = { +@@ -830,15 +1063,602 @@ static const struct ili9881c_instr w552946ab_init[] = { ILI9881C_SWITCH_PAGE_INSTR(0), }; @@ -75315,8 +77844,6 @@ index 7838947a1bf3..971f8ee56308 100644 - * The panel seems to accept some private DCS commands that map - * directly to registers. - * -- * It is organised by page, with each page having its own set of -- * registers, and the first page looks like it's holding the standard + //ILI9881C PAGE1 + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x09), @@ -75765,34 +78292,63 @@ index 7838947a1bf3..971f8ee56308 100644 + * The panel seems to accept some private DCS commands that map + * directly to registers. + * -+ * It is organised by page, with each page having its own set of -+ * registers, and the first page looks like it's holding the standard + * It is organised by page, with each page having its own set of + * registers, and the first page looks like it's holding the standard * DCS commands. - * - * So before any attempt at sending a command or data, we have to be -@@ -883,10 +1696,10 @@ static int ili9881c_prepare(struct drm_panel *panel) - msleep(5); +@@ -914,6 +1734,12 @@ static int ili9881c_prepare(struct drm_panel *panel) + if (ret) + return ret; - /* And reset it */ -- gpiod_set_value(ctx->reset, 1); -+ gpiod_set_value_cansleep(ctx->reset, 1); - msleep(20); ++ if (ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE) { ++ msleep(120); ++ ++ ret = mipi_dsi_dcs_set_display_on(ctx->dsi); ++ } ++ + return 0; + } -- gpiod_set_value(ctx->reset, 0); -+ gpiod_set_value_cansleep(ctx->reset, 0); - msleep(20); +@@ -921,9 +1747,11 @@ static int ili9881c_enable(struct drm_panel *panel) + { + struct ili9881c *ctx = panel_to_ili9881c(panel); - for (i = 0; i < ctx->desc->init_length; i++) { -@@ -941,7 +1754,7 @@ static int ili9881c_unprepare(struct drm_panel *panel) +- msleep(120); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE)) { ++ msleep(120); - mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); - regulator_disable(ctx->power); -- gpiod_set_value(ctx->reset, 1); -+ gpiod_set_value_cansleep(ctx->reset, 1); +- mipi_dsi_dcs_set_display_on(ctx->dsi); ++ mipi_dsi_dcs_set_display_on(ctx->dsi); ++ } return 0; } -@@ -980,6 +1793,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { +@@ -932,14 +1760,23 @@ static int ili9881c_disable(struct drm_panel *panel) + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- return mipi_dsi_dcs_set_display_off(ctx->dsi); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE)) ++ mipi_dsi_dcs_set_display_off(ctx->dsi); ++ ++ return 0; + } + + static int ili9881c_unprepare(struct drm_panel *panel) + { + struct ili9881c *ctx = panel_to_ili9881c(panel); + +- mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); ++ if (!(ctx->desc->flags & ILI9881_FLAGS_NO_SHUTDOWN_CMDS)) { ++ if (ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE) ++ mipi_dsi_dcs_set_display_off(ctx->dsi); ++ ++ mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); ++ } ++ + regulator_disable(ctx->power); + gpiod_set_value_cansleep(ctx->reset, 1); + +@@ -980,6 +1817,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { .height_mm = 217, }; @@ -75816,7 +78372,7 @@ index 7838947a1bf3..971f8ee56308 100644 static const struct drm_display_mode tl050hdv35_default_mode = { .clock = 59400, -@@ -1014,6 +1844,54 @@ static const struct drm_display_mode w552946aba_default_mode = { +@@ -1014,6 +1868,54 @@ static const struct drm_display_mode w552946aba_default_mode = { .height_mm = 121, }; @@ -75871,7 +78427,7 @@ index 7838947a1bf3..971f8ee56308 100644 static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { -@@ -1074,6 +1952,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) +@@ -1074,6 +1976,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) ctx->dsi = dsi; ctx->desc = of_device_get_match_data(&dsi->dev); @@ -75879,23 +78435,23 @@ index 7838947a1bf3..971f8ee56308 100644 drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, DRM_MODE_CONNECTOR_DSI); -@@ -1102,9 +1981,13 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) +@@ -1102,9 +2005,13 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = ctx->desc->mode_flags; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = 4; + dsi->lanes = ctx->desc->lanes; -+ + +- return mipi_dsi_attach(dsi); + ret = mipi_dsi_attach(dsi); + if (ret) + drm_panel_remove(&ctx->panel); - -- return mipi_dsi_attach(dsi); ++ + return ret; } static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) -@@ -1113,6 +1996,9 @@ static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) +@@ -1113,6 +2020,9 @@ static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); @@ -75905,7 +78461,7 @@ index 7838947a1bf3..971f8ee56308 100644 } static const struct ili9881c_desc lhr050h41_desc = { -@@ -1120,6 +2006,7 @@ static const struct ili9881c_desc lhr050h41_desc = { +@@ -1120,6 +2030,7 @@ static const struct ili9881c_desc lhr050h41_desc = { .init_length = ARRAY_SIZE(lhr050h41_init), .mode = &lhr050h41_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, @@ -75913,7 +78469,7 @@ index 7838947a1bf3..971f8ee56308 100644 }; static const struct ili9881c_desc k101_im2byl02_desc = { -@@ -1127,6 +2014,15 @@ static const struct ili9881c_desc k101_im2byl02_desc = { +@@ -1127,6 +2038,15 @@ static const struct ili9881c_desc k101_im2byl02_desc = { .init_length = ARRAY_SIZE(k101_im2byl02_init), .mode = &k101_im2byl02_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, @@ -75929,7 +78485,7 @@ index 7838947a1bf3..971f8ee56308 100644 }; static const struct ili9881c_desc tl050hdv35_desc = { -@@ -1143,13 +2039,42 @@ static const struct ili9881c_desc w552946aba_desc = { +@@ -1143,13 +2063,44 @@ static const struct ili9881c_desc w552946aba_desc = { .mode = &w552946aba_default_mode, .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, @@ -75958,6 +78514,8 @@ index 7838947a1bf3..971f8ee56308 100644 + .mode = &rpi_7inch_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM, + .lanes = 2, ++ .flags = ILI9881_FLAGS_NO_SHUTDOWN_CMDS | ++ ILI9881_FLAGS_PANEL_ON_IN_PREPARE, }; static const struct of_device_id ili9881c_of_match[] = { @@ -76105,7 +78663,7 @@ index 4618c892cdd6..4c418962aa9b 100644 /* Look up the DSI host. It needs to probe before we do. */ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c -index 51f838befb32..0d436f0ec197 100644 +index 11ade6bac592..36cda6335369 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -40,6 +40,7 @@ @@ -76261,7 +78819,7 @@ index 51f838befb32..0d436f0ec197 100644 static const struct drm_display_mode innolux_at070tn92_mode = { .clock = 33333, .hdisplay = 800, -@@ -3372,6 +3412,31 @@ static const struct panel_desc rocktech_rk043fn48h = { +@@ -3376,6 +3416,31 @@ static const struct panel_desc rocktech_rk043fn48h = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -76293,7 +78851,7 @@ index 51f838befb32..0d436f0ec197 100644 static const struct display_timing rocktech_rk070er9427_timing = { .pixelclock = { 26400000, 33300000, 46800000 }, .hactive = { 800, 800, 800 }, -@@ -4269,6 +4334,9 @@ static const struct of_device_id platform_of_match[] = { +@@ -4273,6 +4338,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "friendlyarm,hd702e", .data = &friendlyarm_hd702e, @@ -76303,7 +78861,7 @@ index 51f838befb32..0d436f0ec197 100644 }, { .compatible = "giantplus,gpg482739qs5", .data = &giantplus_gpg482739qs5 -@@ -4290,6 +4358,9 @@ static const struct of_device_id platform_of_match[] = { +@@ -4294,6 +4362,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "innolux,at043tn24", .data = &innolux_at043tn24, @@ -76313,7 +78871,7 @@ index 51f838befb32..0d436f0ec197 100644 }, { .compatible = "innolux,at070tn92", .data = &innolux_at070tn92, -@@ -4422,6 +4493,9 @@ static const struct of_device_id platform_of_match[] = { +@@ -4426,6 +4497,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "rocktech,rk043fn48h", .data = &rocktech_rk043fn48h, @@ -76323,7 +78881,7 @@ index 51f838befb32..0d436f0ec197 100644 }, { .compatible = "rocktech,rk070er9427", .data = &rocktech_rk070er9427, -@@ -4776,6 +4850,9 @@ static const struct panel_desc_dsi osd101t2045_53ts = { +@@ -4780,6 +4854,9 @@ static const struct panel_desc_dsi osd101t2045_53ts = { .lanes = 4, }; @@ -76333,7 +78891,7 @@ index 51f838befb32..0d436f0ec197 100644 static const struct of_device_id dsi_of_match[] = { { .compatible = "auo,b080uan01", -@@ -4798,21 +4875,138 @@ static const struct of_device_id dsi_of_match[] = { +@@ -4802,21 +4879,138 @@ static const struct of_device_id dsi_of_match[] = { }, { .compatible = "osddisplays,osd101t2045-53ts", .data = &osd101t2045_53ts @@ -77354,10 +79912,10 @@ index 000000000000..28c2a33691fd +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-waveshare-dsi.c b/drivers/gpu/drm/panel/panel-waveshare-dsi.c new file mode 100644 -index 000000000000..835b80a6a0ae +index 000000000000..2cca27e4ecc8 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c -@@ -0,0 +1,434 @@ +@@ -0,0 +1,488 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2023 Raspberry Pi Ltd @@ -77510,6 +80068,51 @@ index 000000000000..835b80a6a0ae + .vtotal = 720 + 8 + 4 + 16, +}; + ++/* 5.0inch 720x1280 ++ * https://www.waveshare.com/5inch-dsi-lcd-d.htm ++ */ ++static const struct drm_display_mode ws_panel_5_0_mode = { ++ .clock = 83333, ++ .hdisplay = 720, ++ .hsync_start = 720 + 100, ++ .hsync_end = 720 + 100 + 80, ++ .htotal = 720 + 100 + 80 + 100, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 20, ++ .vsync_end = 1280 + 20 + 20, ++ .vtotal = 1280 + 20 + 20 + 20, ++}; ++ ++/* 6.25inch 720x1560 ++ * https://www.waveshare.com/6.25inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_6_25_mode = { ++ .clock = 83333, ++ .hdisplay = 720, ++ .hsync_start = 720 + 50, ++ .hsync_end = 720 + 50 + 50, ++ .htotal = 720 + 50 + 50 + 50, ++ .vdisplay = 1560, ++ .vsync_start = 1560 + 20, ++ .vsync_end = 1560 + 20 + 20, ++ .vtotal = 1560 + 20 + 20 + 20, ++}; ++ ++/* 8.8inch 480x1920 ++ * https://www.waveshare.com/8.8inch-dsi-lcd.htm ++ */ ++static const struct drm_display_mode ws_panel_8_8_mode = { ++ .clock = 83333, ++ .hdisplay = 480, ++ .hsync_start = 480 + 50, ++ .hsync_end = 480 + 50 + 50, ++ .htotal = 480 + 50 + 50 + 50, ++ .vdisplay = 1920, ++ .vsync_start = 1920 + 20, ++ .vsync_end = 1920 + 20 + 20, ++ .vtotal = 1920 + 20 + 20 + 20, ++}; ++ +static struct ws_panel *panel_to_ts(struct drm_panel *panel) +{ + return container_of(panel, struct ws_panel, base); @@ -77773,6 +80376,15 @@ index 000000000000..835b80a6a0ae + .compatible = "waveshare,4inch-panel", + .data = &ws_panel_4_mode, + }, { ++ .compatible = "waveshare,5.0inch-panel", ++ .data = &ws_panel_5_0_mode, ++ }, { ++ .compatible = "waveshare,6.25inch-panel", ++ .data = &ws_panel_6_25_mode, ++ }, { ++ .compatible = "waveshare,8.8inch-panel", ++ .data = &ws_panel_8_8_mode, ++ }, { + /* sentinel */ + } +}; @@ -77843,10 +80455,10 @@ index 000000000000..79fdc7903167 +obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c new file mode 100644 -index 000000000000..a5a6300770cf +index 000000000000..c97114a89165 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c -@@ -0,0 +1,415 @@ +@@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DPI output on Raspberry Pi RP1 @@ -78109,6 +80721,8 @@ index 000000000000..a5a6300770cf +static const u32 rp1dpi_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 @@ -78855,10 +81469,10 @@ index 000000000000..cd328b98d4da +} diff --git a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c new file mode 100644 -index 000000000000..5b90c69d696a +index 000000000000..e4c2592d8498 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c -@@ -0,0 +1,492 @@ +@@ -0,0 +1,504 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DPI output on Raspberry Pi RP1 @@ -79119,6 +81733,18 @@ index 000000000000..5b90c69d696a + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), @@ -79384,10 +82010,10 @@ index 000000000000..1a9672c7bda0 +obj-$(CONFIG_DRM_RP1_DSI) += drm-rp1-dsi.o diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c new file mode 100644 -index 000000000000..53e0858dd69b +index 000000000000..05d6416ebe3f --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c -@@ -0,0 +1,535 @@ +@@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 @@ -79444,6 +82070,7 @@ index 000000000000..53e0858dd69b + struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); + + rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode); ++ dsi->dsi_running = true; +} + +static void rp1_dsi_bridge_enable(struct drm_bridge *bridge, @@ -79618,6 +82245,8 @@ index 000000000000..53e0858dd69b +static const u32 rp1dsi_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 @@ -79783,7 +82412,10 @@ index 000000000000..53e0858dd69b + return ret; + } + -+ rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), packet.payload_length, packet.payload); ++ rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), ++ packet.payload_length, packet.payload, ++ !!(msg->flags & MIPI_DSI_MSG_USE_LPM), ++ !!(msg->flags & MIPI_DSI_MSG_REQ_ACK)); + + /* Optional read back */ + if (msg->rx_len && msg->rx_buf) @@ -79833,7 +82465,7 @@ index 000000000000..53e0858dd69b + /* Hardware resources */ + for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) { + static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = { -+ "cfgclk", "dpiclk", "byteclk", "refclk" ++ "cfgclk", "dpiclk", "byteclk", "refclk", "pllsys" + }; + dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]); + if (IS_ERR(dsi->clocks[i])) { @@ -79925,10 +82557,10 @@ index 000000000000..53e0858dd69b +MODULE_AUTHOR("Nick Hollinghurst"); diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h new file mode 100644 -index 000000000000..c40186748a3f +index 000000000000..468325ed2480 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h -@@ -0,0 +1,94 @@ +@@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DRM Driver for DSI output on Raspberry Pi RP1 @@ -79961,7 +82593,8 @@ index 000000000000..c40186748a3f +#define RP1DSI_CLOCK_DPI 1 +#define RP1DSI_CLOCK_BYTE 2 +#define RP1DSI_CLOCK_REF 3 -+#define RP1DSI_NUM_CLOCKS 4 ++#define RP1DSI_CLOCK_PLLSYS 4 ++#define RP1DSI_NUM_CLOCKS 5 + +/* ---------------------------------------------------------------------- */ + @@ -80016,7 +82649,8 @@ index 000000000000..c40186748a3f +/* Functions to control the SNPS D-PHY and DSI block setup */ + +void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode); -+void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf); ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf, ++ bool use_lpm, bool req_ack); +int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf); +void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode); +void rp1dsi_dsi_stop(struct rp1_dsi *dsi); @@ -80025,10 +82659,10 @@ index 000000000000..c40186748a3f + diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c new file mode 100644 -index 000000000000..85bb0615bae9 +index 000000000000..86fa351562b4 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c -@@ -0,0 +1,443 @@ +@@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 @@ -80278,6 +82912,18 @@ index 000000000000..85bb0615bae9 + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = ISHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), @@ -80474,10 +83120,10 @@ index 000000000000..85bb0615bae9 +} diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c new file mode 100644 -index 000000000000..7935e00720f3 +index 000000000000..cbcfd8b8eda3 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c -@@ -0,0 +1,1513 @@ +@@ -0,0 +1,1599 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 @@ -80487,6 +83133,7 @@ index 000000000000..7935e00720f3 + +#include +#include ++#include +#include +#include +#include "drm/drm_print.h" @@ -80582,6 +83229,24 @@ index 000000000000..7935e00720f3 + +/* And some bitfield definitions */ + ++#define DSI_PCKHDL_EOTP_TX_EN BIT(0) ++#define DSI_PCKHDL_BTA_EN BIT(2) ++ ++#define DSI_VID_MODE_LP_CMD_EN BIT(15) ++#define DSI_VID_MODE_FRAME_BTA_ACK_EN BIT(14) ++#define DSI_VID_MODE_LP_HFP_EN BIT(13) ++#define DSI_VID_MODE_LP_HBP_EN BIT(12) ++#define DSI_VID_MODE_LP_VACT_EN BIT(11) ++#define DSI_VID_MODE_LP_VFP_EN BIT(10) ++#define DSI_VID_MODE_LP_VBP_EN BIT(9) ++#define DSI_VID_MODE_LP_VSA_EN BIT(8) ++#define DSI_VID_MODE_SYNC_PULSES 0 ++#define DSI_VID_MODE_SYNC_EVENTS 1 ++#define DSI_VID_MODE_BURST 2 ++ ++#define DSI_CMD_MODE_ALL_LP 0x10f7f00 ++#define DSI_CMD_MODE_ACK_RQST_EN BIT(1) ++ +#define DPHY_PWR_UP_SHUTDOWNZ_LSB 0 +#define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB) + @@ -81591,7 +84256,7 @@ index 000000000000..7935e00720f3 + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); +} + -+static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n) ++static u64 dphy_get_div(u32 refclk, u64 vco_freq, u32 *ptr_m, u32 *ptr_n) +{ + /* + * See pg 77-78 of dphy databook @@ -81604,19 +84269,23 @@ index 000000000000..7935e00720f3 + * In practice, given a 50MHz reference clock, it can produce any + * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz + * with < 1% error for all frequencies above 495MHz. ++ * ++ * vco_freq should be set to the lane bit rate (not the MIPI clock ++ * which is half of this). These frequencies are now measured in Hz. ++ * They should fit within u32, but u64 is needed for calculations. + */ + -+ static const u32 REF_DIVN_MAX = 40000u; -+ static const u32 REF_DIVN_MIN = 5000u; -+ u32 best_n, best_m, best_err = 0x7fffffff; -+ unsigned int n; ++ static const u32 REF_DIVN_MAX = 40000000; ++ static const u32 REF_DIVN_MIN = 5000000; ++ u32 n, best_n, best_m; ++ u64 best_err = vco_freq; + -+ for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) { -+ u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz); ++ for (n = 1 + refclk / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk && n < 100; ++n) { ++ u32 half_m = DIV_U64_ROUND_CLOSEST(n * vco_freq, 2 * refclk); + + if (half_m < 150) { -+ u32 f = (2 * half_m * refclk_khz) / n; -+ u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f; ++ u64 f = div_u64(mul_u32_u32(2 * half_m, refclk), n); ++ u64 err = (f > vco_freq) ? f - vco_freq : vco_freq - f; + + if (err < best_err) { + best_n = n; @@ -81628,12 +84297,12 @@ index 000000000000..7935e00720f3 + } + } + -+ if (64 * best_err < vco_freq_khz) { /* tolerate small error */ -+ *ptr_n = best_n; -+ *ptr_m = best_m; -+ return 1; -+ } -+ return 0; ++ if (64 * best_err >= vco_freq) ++ return 0; ++ ++ *ptr_n = best_n; ++ *ptr_m = best_m; ++ return div_u64(mul_u32_u32(best_m, refclk), best_n); +} + +struct hsfreq_range { @@ -81706,13 +84375,14 @@ index 000000000000..7935e00720f3 + hsfreq_table[i].hsfreqrange << 1); +} + -+static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz) ++static u32 dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk, u32 vco_freq) +{ + u32 m = 0; + u32 n = 0; ++ u32 actual_vco_freq = dphy_get_div(refclk, vco_freq, &m, &n); + -+ if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) { -+ dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000); ++ if (actual_vco_freq) { ++ dphy_set_hsfreqrange(dsi, actual_vco_freq / 1000000); + /* Program m,n from registers */ + dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30); + /* N (program N-1) */ @@ -81722,18 +84392,21 @@ index 000000000000..7935e00720f3 + /* M[4:0] (program M-1) */ + dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F)); + drm_dbg_driver(dsi->drm, -+ "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n", -+ vco_freq_khz, refclk_khz * m / n, m, refclk_khz, -+ n, hsfreq_table[dsi->hsfreq_index].hsfreqrange); ++ "DPHY: vco freq want %uHz got %uHz = %d * (%uHz / %d), hsfreqrange = 0x%02x\n", ++ vco_freq, actual_vco_freq, m, refclk, n, ++ hsfreq_table[dsi->hsfreq_index].hsfreqrange); + } else { -+ drm_info(dsi->drm, -+ "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n", -+ vco_freq_khz, m, refclk_khz, n); ++ drm_err(dsi->drm, ++ "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq); + } ++ ++ return actual_vco_freq; +} + -+static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) ++static u32 dphy_init(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) +{ ++ u32 actual_vco_freq; ++ + /* Reset the PHY */ + DSI_WRITE(DSI_PHYRSTZ, 0); + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); @@ -81743,13 +84416,15 @@ index 000000000000..7935e00720f3 + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); + udelay(1); + /* Since we are in DSI (not CSI2) mode here, start the PLL */ -+ dphy_configure_pll(dsi, ref_freq, vco_freq); ++ actual_vco_freq = dphy_configure_pll(dsi, ref_freq, vco_freq); + udelay(1); + /* Unreset */ + DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS); + udelay(1); + DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS)); + udelay(1); /* so we can see PLL coming up? */ ++ ++ return actual_vco_freq; +} + +void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi) @@ -81770,23 +84445,30 @@ index 000000000000..7935e00720f3 + return u; +} + -+static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes) ++static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, u32 byte_clock, ++ unsigned int bpp, unsigned int lanes) +{ -+ unsigned long u; -+ -+ if (dsi->clocks[RP1DSI_CLOCK_DPI]) { -+ u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ? -+ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0; -+ drm_info(dsi->drm, -+ "rp1dsi: Nominal byte clock %lu; scale by %u/%u", -+ u, 4 * lanes, (bpp >> 1)); -+ if (u < 1 || u >= (1ul << 28)) -+ u = 72000000ul; /* default DUMMY frequency for byteclock */ ++ /* Dummy clk_set_rate() to declare the actual DSI byte-clock rate */ ++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_BYTE], byte_clock); + ++ /* ++ * Prefer the DSI byte-clock source where possible, so that DSI and DPI ++ * clocks will be in an exact ratio and downstream devices can recover ++ * perfect timings. But when DPI clock is faster, fall back on PLL_SYS. ++ * To defeat rounding errors, specify explicitly which source to use. ++ */ ++ if (bpp >= 8 * lanes) + clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]); -+ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1)); -+ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); -+ } ++ else if (dsi->clocks[RP1DSI_CLOCK_PLLSYS]) ++ clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_PLLSYS]); ++ ++ clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1)); ++ clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); ++ drm_info(dsi->drm, ++ "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)\n", ++ byte_clock, ++ clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]), ++ clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI]))); +} + +static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi) @@ -81816,48 +84498,65 @@ index 000000000000..7935e00720f3 + return 0x005; +} + -+/* Maximum frequency for LP escape clock (20MHz), and some magic numbers */ -+#define RP1DSI_ESC_CLK_KHZ 20000 -+#define RP1DSI_TO_CLK_DIV 5 -+#define RP1DSI_HSTX_TO_MIN 0x200 -+#define RP1DSI_LPRX_TO_VAL 0x400 ++/* Frequency limits for DPI, HS and LP clocks, and some magic numbers */ ++#define RP1DSI_DPI_MAX_KHZ 200000 ++#define RP1DSI_BYTE_CLK_MIN 10000000 ++#define RP1DSI_BYTE_CLK_MAX 187500000 ++#define RP1DSI_ESC_CLK_MAX 20000000 ++#define RP1DSI_TO_CLK_DIV 0x50 ++#define RP1DSI_LPRX_TO_VAL 0x40 +#define RP1DSI_BTA_TO_VAL 0xd00 + +void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) +{ -+ u32 timeout, mask, vid_mode_cfg; -+ int lane_kbps; ++ int cmdtim; ++ u32 timeout, mask, clkdiv; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); ++ u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes, ++ RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX); + + DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1); + DSI_WRITE(DSI_DPI_CFG_POL, 0); + DSI_WRITE(DSI_GEN_VCID, dsi->vc); + DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format)); -+ /* a conservative guess (LP escape is slow!) */ -+ DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000); + -+ /* Drop to LP where possible; use LP Escape for all commands */ -+ vid_mode_cfg = 0xbf00; -+ if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) -+ vid_mode_cfg |= 0x01; ++ /* ++ * Flags to configure use of LP, EoTp, Burst Mode, Sync Events/Pulses. ++ * Note that Burst Mode implies Sync Events; the two flags need not be ++ * set concurrently, and in this RP1 variant *should not* both be set: ++ * doing so would (counter-intuitively) enable Sync Pulses and may fail ++ * if there is not sufficient time to return to LP11 state during HBP. ++ */ ++ mask = DSI_VID_MODE_LP_HFP_EN | DSI_VID_MODE_LP_HBP_EN | ++ DSI_VID_MODE_LP_VACT_EN | DSI_VID_MODE_LP_VFP_EN | ++ DSI_VID_MODE_LP_VBP_EN | DSI_VID_MODE_LP_VSA_EN; ++ if (dsi->display_flags & MIPI_DSI_MODE_LPM) ++ mask |= DSI_VID_MODE_LP_CMD_EN; + if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) -+ vid_mode_cfg |= 0x02; -+ DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); -+ DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00); ++ mask |= DSI_VID_MODE_BURST; ++ else if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) ++ mask |= DSI_VID_MODE_SYNC_EVENTS; ++ else if (8 * dsi->lanes > bpp) ++ mask &= ~DSI_VID_MODE_LP_HBP_EN; /* PULSE && inexact DPICLK => fix HBP time */ ++ DSI_WRITE(DSI_VID_MODE_CFG, mask); ++ DSI_WRITE(DSI_CMD_MODE_CFG, ++ (dsi->display_flags & MIPI_DSI_MODE_LPM) ? DSI_CMD_MODE_ALL_LP : 0); ++ DSI_WRITE(DSI_PCKHDL_CFG, ++ DSI_PCKHDL_BTA_EN | ++ ((dsi->display_flags & MIPI_DSI_MODE_NO_EOT_PACKET) ? 0 : DSI_PCKHDL_EOTP_TX_EN)); + + /* Select Command Mode */ + DSI_WRITE(DSI_MODE_CFG, 1); + + /* Set timeouts and clock dividers */ -+ DSI_WRITE(DSI_TO_CNT_CFG, -+ (max((bpp * mode->htotal) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes), -+ RP1DSI_HSTX_TO_MIN) << 16) | -+ RP1DSI_LPRX_TO_VAL); ++ timeout = (bpp * mode->htotal * mode->vdisplay) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes); ++ if (timeout > 0xFFFFu) ++ timeout = 0; ++ DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL); + DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL); -+ lane_kbps = (bpp * mode->clock) / dsi->lanes; ++ clkdiv = max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX); /* byte clocks per escape clock */ + DSI_WRITE(DSI_CLKMGR_CFG, -+ (RP1DSI_TO_CLK_DIV << 8) | -+ max(2, lane_kbps / (8 * RP1DSI_ESC_CLK_KHZ) + 1)); ++ (RP1DSI_TO_CLK_DIV << 8) | clkdiv); + + /* Configure video timings */ + DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); @@ -81874,7 +84573,7 @@ index 000000000000..7935e00720f3 + DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay); + + /* Init PHY */ -+ dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, lane_kbps); ++ byte_clock = dphy_init(dsi, rp1dsi_refclk_freq(dsi), 8 * byte_clock) >> 3; + + DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG, + (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | @@ -81883,6 +84582,18 @@ index 000000000000..7935e00720f3 + (hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | + (hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); + ++ /* Estimate how many LP bytes can be sent during vertical blanking (Databook 3.6.2.1) */ ++ cmdtim = mode->htotal; ++ if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ++ cmdtim -= mode->hsync_end - mode->hsync_start; ++ cmdtim = (bpp * cmdtim - 64) / (8 * dsi->lanes); /* byte clocks after HSS and EoTp */ ++ cmdtim -= hsfreq_table[dsi->hsfreq_index].data_hs2lp; ++ cmdtim -= hsfreq_table[dsi->hsfreq_index].data_lp2hs; ++ cmdtim = (cmdtim / clkdiv) - 24; /* escape clocks for commands */ ++ cmdtim = max(0, cmdtim >> 4); /* bytes (at 2 clocks per bit) */ ++ drm_info(dsi->drm, "rp1dsi: Command time (outvact): %d\n", cmdtim); ++ DSI_WRITE(DSI_DPI_LP_CMD_TIM, cmdtim << 16); ++ + /* Wait for PLL lock */ + for (timeout = (1 << 14); timeout != 0; --timeout) { + usleep_range(10, 50); @@ -81892,13 +84603,13 @@ index 000000000000..7935e00720f3 + if (timeout == 0) + drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n"); + -+ DSI_WRITE(DSI_LPCLK_CTRL, 0x1); /* configure the requesthsclk */ ++ DSI_WRITE(DSI_LPCLK_CTRL, ++ (dsi->display_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0x3 : 0x1); + DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2); -+ DSI_WRITE(DSI_PCKHDL_CFG, 1 << 2); /* allow bus turnaround */ + DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ + + /* Now it should be safe to start the external DPI clock divider */ -+ rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes); ++ rp1dsi_dpiclk_start(dsi, byte_clock, bpp, dsi->lanes); + + /* Wait for all lane(s) to be in Stopstate */ + mask = (1 << 4); @@ -81918,7 +84629,8 @@ index 000000000000..7935e00720f3 + mask, DSI_READ(DSI_PHY_STATUS)); +} + -+void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf) ++void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf, ++ bool use_lpm, bool req_ack) +{ + u32 val; + @@ -81929,6 +84641,24 @@ index 000000000000..7935e00720f3 + usleep_range(100, 150); + } + ++ /* ++ * Update global configuration flags for LP/HS and ACK options. ++ * XXX It's not clear if having empty FIFOs (checked above and below) guarantees that ++ * the last command has completed and been ACKed, or how closely these control registers ++ * align with command/payload FIFO writes (as each is an independent clock-crossing)? ++ */ ++ val = DSI_READ(DSI_VID_MODE_CFG); ++ if (use_lpm) ++ val |= DSI_VID_MODE_LP_CMD_EN; ++ else ++ val &= ~DSI_VID_MODE_LP_CMD_EN; ++ DSI_WRITE(DSI_VID_MODE_CFG, val); ++ val = (use_lpm) ? DSI_CMD_MODE_ALL_LP : 0; ++ if (req_ack) ++ val |= DSI_CMD_MODE_ACK_RQST_EN; ++ DSI_WRITE(DSI_CMD_MODE_CFG, val); ++ (void)DSI_READ(DSI_CMD_MODE_CFG); ++ + /* Write payload (in 32-bit words) and header */ + for (; len > 0; len -= 4) { + val = *buf++; @@ -81962,8 +84692,10 @@ index 000000000000..7935e00720f3 + break; + usleep_range(100, 150); + } -+ if (i == 0) ++ if (!i) { ++ drm_warn(dsi->drm, "Receive failed\n"); + return -EIO; ++ } + + for (i = 0; i < len; i += 4) { + /* Read fifo must not be empty before all bytes are read */ @@ -82021,10 +84753,10 @@ index 000000000000..7e941cad342e +obj-$(CONFIG_DRM_RP1_VEC) += drm-rp1-vec.o diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c new file mode 100644 -index 000000000000..9d6cd17e8ac8 +index 000000000000..a7ea68e763eb --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c -@@ -0,0 +1,602 @@ +@@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for VEC output on Raspberry Pi RP1 @@ -82447,6 +85179,8 @@ index 000000000000..9d6cd17e8ac8 +static const u32 rp1vec_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 @@ -82533,8 +85267,8 @@ index 000000000000..9d6cd17e8ac8 + + vec->drm.mode_config.min_width = 256; + vec->drm.mode_config.min_height = 128; -+ vec->drm.mode_config.max_width = 848; /* for System E */ -+ vec->drm.mode_config.max_height = 738; /* for System E */ ++ vec->drm.mode_config.max_width = 960; /* for "widescreen" @ 18MHz */ ++ vec->drm.mode_config.max_height = 738; /* for System E only */ + vec->drm.mode_config.preferred_depth = 32; + vec->drm.mode_config.prefer_shadow = 0; + vec->drm.mode_config.quirk_addfb_prefer_host_byte_order = true; @@ -83221,10 +85955,10 @@ index 000000000000..241dedee5889 +} diff --git a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c new file mode 100644 -index 000000000000..3fb57f7d931c +index 000000000000..1f70ecf42013 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c -@@ -0,0 +1,568 @@ +@@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for VEC output on Raspberry Pi RP1 @@ -83290,6 +86024,18 @@ index 000000000000..3fb57f7d931c + .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), + }, + { ++ .format = DRM_FORMAT_ARGB8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(23, 15, 7), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), ++ .shift = SHIFT_RGB(7, 15, 23), ++ .rgbsz = BITS(VEC_RGBSZ_BYTES_PER_PIXEL_MINUS1, 3), ++ }, ++ { + .format = DRM_FORMAT_RGB888, + .mask = MASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = SHIFT_RGB(23, 15, 7), @@ -83410,7 +86156,7 @@ index 000000000000..3fb57f7d931c + .misc = 0x00091c01, /* 5-tap FIR, SEQ_EN, 8 fld sync, PAL */ + .nco_freq = 0x0a8262b2cc48c1d1, + .timing_regs = { -+ 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, ++ 0x04660cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, + 0x026c0270, 0x00000004, 0x00050009, 0x00070135, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00170136, 0x00000000, @@ -83433,7 +86179,7 @@ index 000000000000..3fb57f7d931c + .misc = 0x0009dc03, /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace, PAL */ + .nco_freq = 0x0a8262b2cc48c1d1, + .timing_regs = { -+ 0x046e0cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, ++ 0x04660cee, 0x0d8001fb, 0x025c034f, 0x00fd0b84, + 0x026c0270, 0x00000004, 0x00050009, 0x00070135, + 0x013f026d, 0x00060136, 0x0140026e, 0x0150026e, + 0x00180136, 0x026f0017, @@ -85219,19 +87965,6 @@ index 000000000000..03632f2e8d4b +#define VEC_DAC_EC_PAL_EN_ACCESS "RW" +// ============================================================================= +#endif // VEC_REGS_DEFINED -diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c -index 78272b1f9d5b..deec6acdcf64 100644 ---- a/drivers/gpu/drm/solomon/ssd130x.c -+++ b/drivers/gpu/drm/solomon/ssd130x.c -@@ -267,7 +267,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) - - pwm_init_state(ssd130x->pwm, &pwmstate); - pwm_set_relative_duty_cycle(&pwmstate, 50, 100); -- pwm_apply_state(ssd130x->pwm, &pwmstate); -+ pwm_apply_might_sleep(ssd130x->pwm, &pwmstate); - - /* Enable the PWM */ - pwm_enable(ssd130x->pwm); diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index 938bceed5999..a6bc9df206a8 100644 --- a/drivers/gpu/drm/tiny/ili9486.c @@ -86941,10 +89674,10 @@ index 62b18f5f41db..d5083695399f 100644 +} diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c new file mode 100644 -index 000000000000..5f4e3013e0ed +index 000000000000..122c2664b093 --- /dev/null +++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c -@@ -0,0 +1,308 @@ +@@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include @@ -87135,6 +89868,7 @@ index 000000000000..5f4e3013e0ed + struct drm_framebuffer *fb; + struct drm_plane *plane; + struct drm_crtc *crtc; ++ struct vc4_dev *vc4; + unsigned int i; + int ret; + @@ -87195,7 +89929,12 @@ index 000000000000..5f4e3013e0ed + ret = drm_atomic_check_only(state); + KUNIT_ASSERT_EQ(test, ret, 0); + -+ KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm_size, params->expected_lbm_size); ++ vc4 = to_vc4_dev(state->dev); ++ KUNIT_ASSERT_NOT_NULL(test, vc4); ++ KUNIT_ASSERT_NOT_NULL(test, vc4->hvs); ++ KUNIT_EXPECT_EQ(test, ++ vc4->hvs->lbm_refcounts[vc4_plane_state->lbm_handle].size, ++ params->expected_lbm_size); + + for (i = 0; i < 2; i++) { + KUNIT_EXPECT_EQ(test, @@ -88030,7 +90769,7 @@ index 86d629e45307..06c791ace2d8 100644 if (!args->len) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index 8b5a7e5eb146..697ced954a50 100644 +index 8b5a7e5eb146..c85737f2b7f7 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -83,13 +83,22 @@ static unsigned int @@ -88151,23 +90890,36 @@ index 8b5a7e5eb146..697ced954a50 100644 static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -@@ -403,6 +443,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode +@@ -338,7 +378,9 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode + bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1; + bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC; + u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; +- u8 ppc = pv_data->pixels_per_clock; ++ u8 ppc = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? ++ pv_data->pixels_per_clock_int : ++ pv_data->pixels_per_clock; + + u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end; + u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start; +@@ -403,6 +445,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode */ CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS | -+ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | ++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ? ++ PV_VCONTROL_ODD_TIMING : 0) | (is_dsi ? PV_VCONTROL_DSI : 0) | PV_VCONTROL_INTERLACE | (odd_field_first -@@ -414,6 +455,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode +@@ -414,6 +458,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode } else { CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS | -+ (vc4->gen >= VC4_GEN_6 ? PV_VCONTROL_ODD_TIMING : 0) | ++ (vc4->gen >= VC4_GEN_6 && ppc == 1 ? ++ PV_VCONTROL_ODD_TIMING : 0) | (is_dsi ? PV_VCONTROL_DSI : 0)); CRTC_WRITE(PV_VSYNCD_EVEN, 0); } -@@ -428,11 +470,17 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode +@@ -428,11 +474,17 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode if (is_dsi) CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); @@ -88186,7 +90938,7 @@ index 8b5a7e5eb146..697ced954a50 100644 CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) | VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | -@@ -458,8 +506,10 @@ static void require_hvs_enabled(struct drm_device *dev) +@@ -458,8 +510,10 @@ static void require_hvs_enabled(struct drm_device *dev) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; @@ -88199,7 +90951,7 @@ index 8b5a7e5eb146..697ced954a50 100644 } static int vc4_crtc_disable(struct drm_crtc *crtc, -@@ -529,7 +579,11 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) +@@ -529,7 +583,11 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node, "brcm,bcm2711-pixelvalve2") || of_device_is_compatible(vc4_crtc->pdev->dev.of_node, @@ -88212,7 +90964,7 @@ index 8b5a7e5eb146..697ced954a50 100644 return 0; if (!(CRTC_READ(PV_CONTROL) & PV_CONTROL_EN)) -@@ -603,6 +657,8 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, +@@ -603,11 +661,14 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, vc4_crtc_disable(crtc, encoder, state, old_vc4_state->assigned_channel); @@ -88221,7 +90973,13 @@ index 8b5a7e5eb146..697ced954a50 100644 /* * Make sure we issue a vblank event after disabling the CRTC if * someone was waiting it. -@@ -735,10 +791,16 @@ int vc4_crtc_atomic_check(struct drm_crtc *crtc, + */ + vc4_crtc_send_vblank(crtc); ++ msleep(20); + } + + static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, +@@ -735,10 +796,16 @@ int vc4_crtc_atomic_check(struct drm_crtc *crtc, if (conn_state->crtc != crtc) continue; @@ -88242,7 +91000,7 @@ index 8b5a7e5eb146..697ced954a50 100644 break; } -@@ -765,12 +827,15 @@ static void vc4_disable_vblank(struct drm_crtc *crtc) +@@ -765,12 +832,15 @@ static void vc4_disable_vblank(struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -88259,7 +91017,7 @@ index 8b5a7e5eb146..697ced954a50 100644 drm_dev_exit(idx); } -@@ -781,14 +846,21 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) +@@ -781,14 +851,21 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; @@ -88283,7 +91041,7 @@ index 8b5a7e5eb146..697ced954a50 100644 drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; drm_crtc_vblank_put(crtc); -@@ -799,7 +871,8 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) +@@ -799,7 +876,8 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) * the CRTC and encoder already reconfigured, leading to * underruns. This can be seen when reconfiguring the CRTC. */ @@ -88293,7 +91051,7 @@ index 8b5a7e5eb146..697ced954a50 100644 } spin_unlock(&vc4_crtc->irq_lock); spin_unlock_irqrestore(&dev->event_lock, flags); -@@ -807,7 +880,14 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) +@@ -807,7 +885,14 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) void vc4_crtc_handle_vblank(struct vc4_crtc *crtc) { @@ -88308,7 +91066,7 @@ index 8b5a7e5eb146..697ced954a50 100644 drm_crtc_handle_vblank(&crtc->base); vc4_crtc_handle_page_flip(crtc); } -@@ -913,7 +993,7 @@ static int vc4_async_set_fence_cb(struct drm_device *dev, +@@ -913,7 +998,7 @@ static int vc4_async_set_fence_cb(struct drm_device *dev, struct dma_fence *fence; int ret; @@ -88317,7 +91075,7 @@ index 8b5a7e5eb146..697ced954a50 100644 struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno, -@@ -1000,7 +1080,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, +@@ -1000,7 +1085,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); int ret; @@ -88326,7 +91084,7 @@ index 8b5a7e5eb146..697ced954a50 100644 return -ENODEV; /* -@@ -1043,7 +1123,7 @@ int vc4_page_flip(struct drm_crtc *crtc, +@@ -1043,7 +1128,7 @@ int vc4_page_flip(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); @@ -88335,7 +91093,7 @@ index 8b5a7e5eb146..697ced954a50 100644 return vc5_async_page_flip(crtc, fb, event, flags); else return vc4_async_page_flip(crtc, fb, event, flags); -@@ -1074,14 +1154,8 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc, +@@ -1074,14 +1159,8 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc, struct vc4_dev *vc4 = to_vc4_dev(crtc->dev); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); @@ -88352,10 +91110,72 @@ index 8b5a7e5eb146..697ced954a50 100644 drm_atomic_helper_crtc_destroy_state(crtc, state); } -@@ -1257,6 +1331,32 @@ const struct vc4_pv_data bcm2711_pv4_data = { +@@ -1149,6 +1228,7 @@ const struct vc4_pv_data bcm2835_pv0_data = { }, - }; - + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI, +@@ -1164,6 +1244,7 @@ const struct vc4_pv_data bcm2835_pv1_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI, +@@ -1179,6 +1260,7 @@ const struct vc4_pv_data bcm2835_pv2_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0, + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, +@@ -1194,6 +1276,7 @@ const struct vc4_pv_data bcm2711_pv0_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_DSI0, + [1] = VC4_ENCODER_TYPE_DPI, +@@ -1209,6 +1292,7 @@ const struct vc4_pv_data bcm2711_pv1_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_DSI1, + [1] = VC4_ENCODER_TYPE_SMI, +@@ -1224,6 +1308,7 @@ const struct vc4_pv_data bcm2711_pv2_data = { + }, + .fifo_depth = 256, + .pixels_per_clock = 2, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI0, + }, +@@ -1238,6 +1323,7 @@ const struct vc4_pv_data bcm2711_pv3_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, + }, +@@ -1252,6 +1338,35 @@ const struct vc4_pv_data bcm2711_pv4_data = { + }, + .fifo_depth = 64, + .pixels_per_clock = 2, ++ .pixels_per_clock_int = 2, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_HDMI1, ++ }, ++}; ++ +const struct vc4_pv_data bcm2712_pv0_data = { + .base = { + .debugfs_name = "crtc0_regs", @@ -88364,6 +91184,7 @@ index 8b5a7e5eb146..697ced954a50 100644 + }, + .fifo_depth = 64, + .pixels_per_clock = 1, ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI0, + }, @@ -88377,15 +91198,11 @@ index 8b5a7e5eb146..697ced954a50 100644 + }, + .fifo_depth = 64, + .pixels_per_clock = 1, -+ .encoder_types = { -+ [0] = VC4_ENCODER_TYPE_HDMI1, -+ }, -+}; -+ - static const struct of_device_id vc4_crtc_dt_match[] = { - { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, - { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, -@@ -1266,6 +1366,8 @@ static const struct of_device_id vc4_crtc_dt_match[] = { ++ .pixels_per_clock_int = 2, + .encoder_types = { + [0] = VC4_ENCODER_TYPE_HDMI1, + }, +@@ -1266,6 +1381,8 @@ static const struct of_device_id vc4_crtc_dt_match[] = { { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data }, { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data }, { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data }, @@ -88394,7 +91211,7 @@ index 8b5a7e5eb146..697ced954a50 100644 {} }; -@@ -1338,21 +1440,38 @@ int __vc4_crtc_init(struct drm_device *drm, +@@ -1338,21 +1455,38 @@ int __vc4_crtc_init(struct drm_device *drm, drm_crtc_helper_add(crtc, crtc_helper_funcs); @@ -88455,6 +91272,60 @@ index fac624a663ea..8144dedf2248 100644 if (vc4->v3d) { drm_WARN_ON(drm, vc4_bo_debugfs_init(minor)); +diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c +index 39152e755a13..305a34e82139 100644 +--- a/drivers/gpu/drm/vc4/vc4_dpi.c ++++ b/drivers/gpu/drm/vc4/vc4_dpi.c +@@ -95,6 +95,8 @@ struct vc4_dpi { + struct clk *core_clock; + + struct debugfs_regset32 regset; ++ ++ int rgb_order_override; + }; + + #define to_vc4_dpi(_encoder) \ +@@ -205,6 +207,11 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) + } + } + ++ if (dpi->rgb_order_override >= 0) { ++ dpi_c &= ~DPI_ORDER_MASK; ++ dpi_c |= VC4_SET_FIELD(dpi->rgb_order_override, DPI_ORDER); ++ } ++ + if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) + dpi_c |= DPI_PIXEL_CLK_INVERT; + +@@ -313,6 +320,7 @@ static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); ++ const char *rgb_order = NULL; + struct vc4_dpi *dpi; + int ret; + +@@ -361,6 +369,20 @@ static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) + if (ret) + return ret; + ++ dpi->rgb_order_override = -1; ++ if (!of_property_read_string(dev->of_node, "rgb_order", &rgb_order)) { ++ if (!strcmp(rgb_order, "rgb")) ++ dpi->rgb_order_override = DPI_ORDER_RGB; ++ else if (!strcmp(rgb_order, "bgr")) ++ dpi->rgb_order_override = DPI_ORDER_BGR; ++ else if (!strcmp(rgb_order, "grb")) ++ dpi->rgb_order_override = DPI_ORDER_GRB; ++ else if (!strcmp(rgb_order, "brg")) ++ dpi->rgb_order_override = DPI_ORDER_BRG; ++ else ++ DRM_ERROR("Invalid dpi order %s - ignored\n", rgb_order); ++ } ++ + ret = drmm_encoder_init(drm, &dpi->encoder.base, + &vc4_dpi_encoder_funcs, + DRM_MODE_ENCODER_DPI, diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 1b3531374967..220e8625402b 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c @@ -88686,7 +91557,7 @@ index 1b3531374967..220e8625402b 100644 { .compatible = "brcm,cygnus-vc4", }, {}, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h -index bf66499765fb..c48314604b9e 100644 +index bf66499765fb..0868cdbf1fce 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -14,6 +14,7 @@ @@ -88734,10 +91605,36 @@ index bf66499765fb..c48314604b9e 100644 struct vc4_hang_state *hang_state; -@@ -309,13 +322,22 @@ struct vc4_v3d { +@@ -309,13 +322,48 @@ struct vc4_v3d { struct debugfs_regset32 regset; }; ++#define VC4_NUM_LBM_HANDLES 64 ++struct vc4_lbm_refcounts { ++ refcount_t refcount; ++ ++ /* Allocation size */ ++ size_t size; ++ /* Our allocation in LBM. */ ++ struct drm_mm_node lbm; ++ ++ /* Pointer back to the HVS structure */ ++ struct vc4_hvs *hvs; ++}; ++ ++#define VC4_NUM_UPM_HANDLES 32 ++struct vc4_upm_refcounts { ++ refcount_t refcount; ++ ++ /* Allocation size */ ++ size_t size; ++ /* Our allocation in UPM for prefetching. */ ++ struct drm_mm_node upm; ++ ++ /* Pointer back to the HVS structure */ ++ struct vc4_hvs *hvs; ++}; ++ +#define HVS_NUM_CHANNELS 3 + struct vc4_hvs { @@ -88757,14 +91654,20 @@ index bf66499765fb..c48314604b9e 100644 unsigned long max_core_rate; -@@ -325,8 +347,16 @@ struct vc4_hvs { +@@ -323,11 +371,24 @@ struct vc4_hvs { + * list. Units are dwords. + */ struct drm_mm dlist_mm; ++ /* Memory manager for the LBM memory used by HVS scaling. */ struct drm_mm lbm_mm; ++ struct ida lbm_handles; ++ struct vc4_lbm_refcounts lbm_refcounts[VC4_NUM_LBM_HANDLES + 1]; + + /* Memory manager for the UPM memory used for prefetching. */ + struct drm_mm upm_mm; + struct ida upm_handles; ++ struct vc4_upm_refcounts upm_refcounts[VC4_NUM_UPM_HANDLES + 1]; + spinlock_t mm_lock; @@ -88772,9 +91675,11 @@ index bf66499765fb..c48314604b9e 100644 + struct work_struct free_dlist_work; + struct drm_mm_node mitchell_netravali_filter; ++ struct drm_mm_node nearest_neighbour_filter; struct debugfs_regset32 regset; -@@ -346,7 +376,7 @@ struct vc4_hvs { + +@@ -346,7 +407,7 @@ struct vc4_hvs { bool vc5_hdmi_enable_4096by2160; }; @@ -88783,14 +91688,7 @@ index bf66499765fb..c48314604b9e 100644 struct vc4_hvs_state { struct drm_private_state base; -@@ -388,12 +418,14 @@ struct vc4_plane_state { - u32 dlist_size; /* Number of dwords allocated for the display list */ - u32 dlist_count; /* Number of used dwords in the display list. */ - -+ u32 lbm_size; /* LBM requirements for this plane */ -+ - /* Offset in the dlist to various words, for pageflip or - * cursor updates. +@@ -393,7 +454,7 @@ struct vc4_plane_state { */ u32 pos0_offset; u32 pos2_offset; @@ -88799,7 +91697,7 @@ index bf66499765fb..c48314604b9e 100644 u32 lbm_offset; /* Offset where the plane's dlist was last stored in the -@@ -403,7 +435,7 @@ struct vc4_plane_state { +@@ -403,7 +464,7 @@ struct vc4_plane_state { /* Clipped coordinates of the plane on the display. */ int crtc_x, crtc_y, crtc_w, crtc_h; @@ -88808,7 +91706,7 @@ index bf66499765fb..c48314604b9e 100644 u32 src_x, src_y; u32 src_w[2], src_h[2]; -@@ -413,13 +445,14 @@ struct vc4_plane_state { +@@ -413,13 +474,14 @@ struct vc4_plane_state { bool is_unity; bool is_yuv; @@ -88816,11 +91714,11 @@ index bf66499765fb..c48314604b9e 100644 - * BO. - */ - u32 offsets[3]; -+ /* Our allocation in UPM for prefetching. */ -+ struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES]; - -- /* Our allocation in LBM for temporary storage during scaling. */ +- + /* Our allocation in LBM for temporary storage during scaling. */ - struct drm_mm_node lbm; ++ unsigned int lbm_handle; ++ + /* The Unified Pre-Fetcher Handle */ + unsigned int upm_handle[DRM_FORMAT_MAX_PLANES]; + @@ -88829,7 +91727,7 @@ index bf66499765fb..c48314604b9e 100644 /* Set when the plane has per-pixel alpha content or does not cover * the entire screen. This is a hint to the CRTC that it might need -@@ -455,7 +488,8 @@ enum vc4_encoder_type { +@@ -455,7 +517,8 @@ enum vc4_encoder_type { VC4_ENCODER_TYPE_DSI1, VC4_ENCODER_TYPE_SMI, VC4_ENCODER_TYPE_DPI, @@ -88839,7 +91737,7 @@ index bf66499765fb..c48314604b9e 100644 }; struct vc4_encoder { -@@ -469,6 +503,7 @@ struct vc4_encoder { +@@ -469,6 +532,7 @@ struct vc4_encoder { void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state); void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state); @@ -88847,7 +91745,7 @@ index bf66499765fb..c48314604b9e 100644 }; #define to_vc4_encoder(_encoder) \ -@@ -490,6 +525,17 @@ struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm, +@@ -490,6 +554,17 @@ struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm, return NULL; } @@ -88865,7 +91763,7 @@ index bf66499765fb..c48314604b9e 100644 struct vc4_crtc_data { const char *name; -@@ -502,7 +548,18 @@ struct vc4_crtc_data { +@@ -502,7 +577,18 @@ struct vc4_crtc_data { int hvs_output; }; @@ -88885,7 +91783,16 @@ index bf66499765fb..c48314604b9e 100644 struct vc4_pv_data { struct vc4_crtc_data base; -@@ -524,6 +581,8 @@ extern const struct vc4_pv_data bcm2711_pv1_data; +@@ -512,6 +598,8 @@ struct vc4_pv_data { + + /* Number of pixels output per clock period */ + u8 pixels_per_clock; ++ /* Number of pixels output per clock period when in an interlaced mode */ ++ u8 pixels_per_clock_int; + + enum vc4_encoder_type encoder_types[4]; + }; +@@ -524,6 +612,8 @@ extern const struct vc4_pv_data bcm2711_pv1_data; extern const struct vc4_pv_data bcm2711_pv2_data; extern const struct vc4_pv_data bcm2711_pv3_data; extern const struct vc4_pv_data bcm2711_pv4_data; @@ -88894,7 +91801,7 @@ index bf66499765fb..c48314604b9e 100644 struct vc4_crtc { struct drm_crtc base; -@@ -534,9 +593,19 @@ struct vc4_crtc { +@@ -534,9 +624,19 @@ struct vc4_crtc { /* Timestamp at start of vblank irq - unaffected by lock delays. */ ktime_t t_vblank; @@ -88917,17 +91824,7 @@ index bf66499765fb..c48314604b9e 100644 struct drm_pending_vblank_event *event; -@@ -568,6 +637,9 @@ struct vc4_crtc { - * access to that value. - */ - unsigned int current_hvs_channel; -+ -+ /* @lbm: Our allocation in LBM for temporary storage during scaling. */ -+ struct drm_mm_node lbm; - }; - - #define to_vc4_crtc(_crtc) \ -@@ -587,22 +659,27 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) +@@ -587,22 +687,27 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) return container_of_const(data, struct vc4_pv_data, base); } @@ -88963,7 +91860,7 @@ index bf66499765fb..c48314604b9e 100644 unsigned long hvs_load; -@@ -639,6 +716,12 @@ struct vc4_crtc_state { +@@ -639,6 +744,12 @@ struct vc4_crtc_state { writel(val, hvs->regs + (offset)); \ } while (0) @@ -88976,7 +91873,7 @@ index bf66499765fb..c48314604b9e 100644 #define VC4_REG32(reg) { .name = #reg, .offset = reg } struct vc4_exec_info { -@@ -963,6 +1046,9 @@ extern struct platform_driver vc4_dsi_driver; +@@ -963,6 +1074,9 @@ extern struct platform_driver vc4_dsi_driver; /* vc4_fence.c */ extern const struct dma_fence_ops vc4_fence_ops; @@ -88986,7 +91883,7 @@ index bf66499765fb..c48314604b9e 100644 /* vc4_gem.c */ int vc4_gem_init(struct drm_device *dev); int vc4_submit_cl_ioctl(struct drm_device *dev, void *data, -@@ -1001,10 +1087,14 @@ void vc4_irq_reset(struct drm_device *dev); +@@ -1001,10 +1115,14 @@ void vc4_irq_reset(struct drm_device *dev); /* vc4_hvs.c */ extern struct platform_driver vc4_hvs_driver; @@ -89002,7 +91899,7 @@ index bf66499765fb..c48314604b9e 100644 int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state); -@@ -1022,6 +1112,12 @@ int vc4_kms_load(struct drm_device *dev); +@@ -1022,6 +1140,12 @@ int vc4_kms_load(struct drm_device *dev); struct drm_plane *vc4_plane_init(struct drm_device *dev, enum drm_plane_type type, uint32_t possible_crtcs); @@ -89016,10 +91913,19 @@ index bf66499765fb..c48314604b9e 100644 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); u32 vc4_plane_dlist_size(const struct drm_plane_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c -index 46f6c4ce61c5..894154d824ab 100644 +index 46f6c4ce61c5..78f232656172 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c -@@ -358,6 +358,16 @@ +@@ -286,6 +286,8 @@ + DSI1_INT_PR_TO) + + #define DSI0_STAT 0x2c ++# define DSI0_STAT_ERR_CONT_LP1 BIT(6) ++# define DSI0_STAT_ERR_CONT_LP0 BIT(5) + #define DSI0_HSTX_TO_CNT 0x30 + #define DSI0_LPRX_TO_CNT 0x34 + #define DSI0_TA_TO_CNT 0x38 +@@ -358,6 +360,16 @@ # define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) # define DSI_PHY_AFEC0_CTATADJ_SHIFT 0 @@ -89036,7 +91942,7 @@ index 46f6c4ce61c5..894154d824ab 100644 #define DSI0_PHY_AFEC1 0x68 # define DSI0_PHY_AFEC1_IDR_DLANE1_MASK VC4_MASK(10, 8) # define DSI0_PHY_AFEC1_IDR_DLANE1_SHIFT 8 -@@ -398,7 +408,8 @@ +@@ -398,7 +410,8 @@ # define DSI1_CTRL_DISABLE_DISP_ECCC BIT(1) # define DSI0_CTRL_CTRL0 BIT(0) # define DSI1_CTRL_EN BIT(0) @@ -89046,11 +91952,10 @@ index 46f6c4ce61c5..894154d824ab 100644 DSI0_CTRL_CLR_PBCF | \ DSI0_CTRL_CLR_CPBCF | \ DSI0_CTRL_CLR_PDF | \ -@@ -807,6 +818,16 @@ static void vc4_dsi_bridge_disable(struct drm_bridge *bridge, - disp0_ctrl = DSI_PORT_READ(DISP0_CTRL); - disp0_ctrl &= ~DSI_DISP0_ENABLE; - DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); -+ +@@ -815,6 +828,15 @@ static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge, + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); + struct device *dev = &dsi->pdev->dev; + + /* Reset the DSI and all its fifos. */ + DSI_PORT_WRITE(CTRL, DSI_CTRL_SOFT_RESET_CFG | + DSI_PORT_BIT(CTRL_RESET_FIFOS)); @@ -89060,10 +91965,10 @@ index 46f6c4ce61c5..894154d824ab 100644 + DSI_PORT_BIT(PHY_AFEC0_PD) | + DSI_PORT_BIT(AFEC0_PD_ALL_LANES)); + - } - - static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge, -@@ -845,6 +866,7 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge, + clk_disable_unprepare(dsi->pll_phy_clock); + clk_disable_unprepare(dsi->escape_clock); + clk_disable_unprepare(dsi->pixel_clock); +@@ -845,6 +867,7 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge, unsigned long pixel_clock_hz = mode->clock * 1000; unsigned long pll_clock = pixel_clock_hz * dsi->divider; int divider; @@ -89071,7 +91976,7 @@ index 46f6c4ce61c5..894154d824ab 100644 /* Find what divider gets us a faster clock than the requested * pixel clock. -@@ -861,12 +883,27 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge, +@@ -861,12 +884,27 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge, pixel_clock_hz = pll_clock / dsi->divider; adjusted_mode->clock = pixel_clock_hz / 1000; @@ -89102,7 +92007,7 @@ index 46f6c4ce61c5..894154d824ab 100644 return true; } -@@ -926,12 +963,31 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, +@@ -926,12 +964,31 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, "Failed to set phy clock to %ld: %d\n", phy_clock, ret); } @@ -89135,7 +92040,7 @@ index 46f6c4ce61c5..894154d824ab 100644 DSI_CTRL_HSDT_EOT_DISABLE | DSI_CTRL_RX_LPDT_EOT_DISABLE); -@@ -984,20 +1040,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, +@@ -984,20 +1041,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, mdelay(1); } @@ -89156,7 +92061,7 @@ index 46f6c4ce61c5..894154d824ab 100644 /* Yes, we set the DSI0P/DSI1P pixel clock to the byte rate, * not the pixel clock rate. DSIxP take from the APHY's byte, * DDR2, or DDR4 clock (we use byte) and feed into the PV at -@@ -1113,12 +1155,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, +@@ -1113,12 +1156,6 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge, DSI_DISP1_PFORMAT) | DSI_DISP1_ENABLE); @@ -89169,7 +92074,88 @@ index 46f6c4ce61c5..894154d824ab 100644 /* Bring AFE out of reset. */ DSI_PORT_WRITE(PHY_AFEC0, DSI_PORT_READ(PHY_AFEC0) & -@@ -1418,6 +1454,15 @@ static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = { +@@ -1168,10 +1205,9 @@ static int vc4_dsi_bridge_attach(struct drm_bridge *bridge, + &dsi->bridge, flags); + } + +-static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, +- const struct mipi_dsi_msg *msg) ++static ssize_t vc4_dsi_transfer(struct vc4_dsi *dsi, ++ const struct mipi_dsi_msg *msg, bool log_error) + { +- struct vc4_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + u32 pkth = 0, pktc = 0; + int i, ret; +@@ -1280,10 +1316,12 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, + DSI_PORT_WRITE(TXPKT1C, pktc); + + if (!wait_for_completion_timeout(&dsi->xfer_completion, +- msecs_to_jiffies(1000))) { +- dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); +- dev_err(&dsi->pdev->dev, "instat: 0x%08x\n", +- DSI_PORT_READ(INT_STAT)); ++ msecs_to_jiffies(500))) { ++ if (log_error) { ++ dev_err(&dsi->pdev->dev, "transfer interrupt wait timeout"); ++ dev_err(&dsi->pdev->dev, "instat: 0x%08x, stat: 0x%08x\n", ++ DSI_PORT_READ(INT_STAT), DSI_PORT_READ(INT_STAT)); ++ } + ret = -ETIMEDOUT; + } else { + ret = dsi->xfer_result; +@@ -1326,7 +1364,8 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, + return ret; + + reset_fifo_and_return: +- DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); ++ if (log_error) ++ DRM_ERROR("DSI transfer failed, resetting: %d\n", ret); + + DSI_PORT_WRITE(TXPKT1C, DSI_PORT_READ(TXPKT1C) & ~DSI_TXPKT1C_CMD_EN); + udelay(1); +@@ -1339,6 +1378,40 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, + return ret; + } + ++static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, ++ const struct mipi_dsi_msg *msg) ++{ ++ struct vc4_dsi *dsi = host_to_dsi(host); ++ u32 stat, disp0_ctrl; ++ int ret; ++ ++ ret = vc4_dsi_transfer(dsi, msg, false); ++ ++ if (ret == -ETIMEDOUT) { ++ stat = DSI_PORT_READ(STAT); ++ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL); ++ ++ DSI_PORT_WRITE(STAT, DSI_PORT_BIT(STAT_ERR_CONT_LP1)); ++ if (!(disp0_ctrl & DSI_DISP0_ENABLE)) { ++ /* If video mode not enabled, then try recovering by ++ * enabling it briefly to clear FIFOs and the state. ++ */ ++ disp0_ctrl |= DSI_DISP0_ENABLE; ++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); ++ msleep(30); ++ disp0_ctrl &= ~DSI_DISP0_ENABLE; ++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl); ++ msleep(30); ++ ++ ret = vc4_dsi_transfer(dsi, msg, true); ++ } else { ++ DRM_ERROR("DSI transfer failed whilst in HS mode stat: 0x%08x\n", ++ stat); ++ } ++ } ++ return ret; ++} ++ + static const struct component_ops vc4_dsi_ops; + static int vc4_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +@@ -1418,6 +1491,15 @@ static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = { .mode_fixup = vc4_dsi_bridge_mode_fixup, }; @@ -89185,7 +92171,7 @@ index 46f6c4ce61c5..894154d824ab 100644 static int vc4_dsi_late_register(struct drm_encoder *encoder) { struct drm_device *drm = encoder->dev; -@@ -1662,6 +1707,9 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) +@@ -1662,6 +1744,9 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) dsi->encoder.type = dsi->variant->port ? VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0; @@ -91391,7 +94377,7 @@ index 03648f954985..0d94165d4b6b 100644 switch (args->madv) { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c -index 4626fe9aac56..e42b431c29af 100644 +index c6e986f71a26..e1f2ce494241 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -41,6 +41,8 @@ @@ -91476,9 +94462,9 @@ index 4626fe9aac56..e42b431c29af 100644 if (!edid) return; -@@ -472,7 +496,9 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, - - WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); +@@ -478,7 +502,9 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, + return connector_status_unknown; + } - if (vc4_hdmi->hpd_gpio) { + if (force_hotplug & BIT(vc4_hdmi->encoder.type - VC4_ENCODER_TYPE_HDMI0)) @@ -91487,7 +94473,76 @@ index 4626fe9aac56..e42b431c29af 100644 if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) status = connector_status_connected; } else { -@@ -748,7 +774,6 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, +@@ -579,6 +605,7 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, + + if (old_state->colorspace != new_state->colorspace || + old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb || ++ old_vc4_state->requested_output_format != new_vc4_state->requested_output_format || + !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { + struct drm_crtc_state *crtc_state; + +@@ -605,6 +632,8 @@ static int vc4_hdmi_connector_get_property(struct drm_connector *connector, + + if (property == vc4_hdmi->broadcast_rgb_property) { + *val = vc4_conn_state->broadcast_rgb; ++ } else if (property == vc4_hdmi->output_format_property) { ++ *val = vc4_conn_state->requested_output_format; + } else { + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); +@@ -628,6 +657,9 @@ static int vc4_hdmi_connector_set_property(struct drm_connector *connector, + if (property == vc4_hdmi->broadcast_rgb_property) { + vc4_conn_state->broadcast_rgb = val; + return 0; ++ } else if (property == vc4_hdmi->output_format_property) { ++ vc4_conn_state->requested_output_format = val; ++ return 0; + } + + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", +@@ -672,6 +704,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) + new_state->tmds_char_rate = vc4_state->tmds_char_rate; + new_state->output_bpc = vc4_state->output_bpc; + new_state->output_format = vc4_state->output_format; ++ new_state->requested_output_format = vc4_state->requested_output_format; + new_state->broadcast_rgb = vc4_state->broadcast_rgb; + __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); + +@@ -720,6 +753,33 @@ vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, + VC4_HDMI_BROADCAST_RGB_AUTO); + } + ++static const struct drm_prop_enum_list output_format_names[] = { ++ { VC4_HDMI_OUTPUT_AUTO, "Automatic" }, ++ { VC4_HDMI_OUTPUT_RGB, "RGB" }, ++ { VC4_HDMI_OUTPUT_YUV422, "YCbCr 4:2:2" }, ++ { VC4_HDMI_OUTPUT_YUV444, "YCbCr 4:4:4" }, ++}; ++ ++static void ++vc4_hdmi_attach_output_format_property(struct drm_device *dev, ++ struct vc4_hdmi *vc4_hdmi) ++{ ++ struct drm_property *prop = vc4_hdmi->output_format_property; ++ ++ if (!prop) { ++ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, ++ "Output format", ++ output_format_names, ++ ARRAY_SIZE(output_format_names)); ++ if (!prop) ++ return; ++ ++ vc4_hdmi->output_format_property = prop; ++ } ++ ++ drm_object_attach_property(&vc4_hdmi->connector.base, prop, 0); ++} ++ + static int vc4_hdmi_connector_init(struct drm_device *dev, + struct vc4_hdmi *vc4_hdmi) + { +@@ -754,7 +814,6 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, drm_connector_attach_colorspace_property(connector); drm_connector_attach_tv_margin_properties(connector); @@ -91495,7 +94550,7 @@ index 4626fe9aac56..e42b431c29af 100644 connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT); -@@ -757,8 +782,12 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, +@@ -763,10 +822,15 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, connector->doublescan_allowed = 0; connector->stereo_allowed = 1; @@ -91508,8 +94563,11 @@ index 4626fe9aac56..e42b431c29af 100644 + } vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); ++ vc4_hdmi_attach_output_format_property(dev, vc4_hdmi); -@@ -1087,6 +1116,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, + drm_connector_attach_encoder(connector, encoder); + +@@ -1093,6 +1157,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_device *drm = vc4_hdmi->connector.dev; @@ -91517,7 +94575,7 @@ index 4626fe9aac56..e42b431c29af 100644 unsigned long flags; int idx; -@@ -1103,14 +1133,25 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, +@@ -1109,14 +1174,25 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB); @@ -91547,7 +94605,16 @@ index 4626fe9aac56..e42b431c29af 100644 vc4_hdmi_disable_scrambling(encoder); -@@ -1738,7 +1779,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, +@@ -1148,6 +1224,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, + if (vc4_hdmi->variant->phy_disable) + vc4_hdmi->variant->phy_disable(vc4_hdmi); + ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, 0); + clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock); + clk_disable_unprepare(vc4_hdmi->pixel_clock); + +@@ -1744,7 +1822,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, goto err_put_runtime_pm; } @@ -91555,20 +94622,40 @@ index 4626fe9aac56..e42b431c29af 100644 vc4_hdmi_cec_update_clk_div(vc4_hdmi); if (tmds_char_rate > 297000000) -@@ -1843,10 +1883,12 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, +@@ -1849,12 +1926,15 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, -+ HDMI_READ(HDMI_VID_CTL) | - VC4_HD_VID_CTL_ENABLE | - VC4_HD_VID_CTL_CLRRGB | - VC4_HD_VID_CTL_UNDERFLOW_ENABLE | - VC4_HD_VID_CTL_FRAME_COUNTER_RESET | -+ VC4_HD_VID_CTL_BLANK_INSERT_EN | - (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | - (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); +- VC4_HD_VID_CTL_ENABLE | +- VC4_HD_VID_CTL_CLRRGB | +- VC4_HD_VID_CTL_UNDERFLOW_ENABLE | +- VC4_HD_VID_CTL_FRAME_COUNTER_RESET | +- (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | +- (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ (HDMI_READ(HDMI_VID_CTL) &~ ++ (VC4_HD_VID_CTL_VSYNC_LOW | VC4_HD_VID_CTL_HSYNC_LOW)) | ++ VC4_HD_VID_CTL_ENABLE | ++ VC4_HD_VID_CTL_CLRRGB | ++ VC4_HD_VID_CTL_UNDERFLOW_ENABLE | ++ VC4_HD_VID_CTL_FRAME_COUNTER_RESET | ++ VC4_HD_VID_CTL_BLANK_INSERT_EN | ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); -@@ -1944,9 +1986,6 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, + HDMI_WRITE(HDMI_VID_CTL, + HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_BLANKPIX); +@@ -1923,6 +2003,10 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, + &crtc_state->adjusted_mode); + vc4_hdmi->output_bpc = vc4_state->output_bpc; + vc4_hdmi->output_format = vc4_state->output_format; ++ vc4_hdmi->requested_output_format = vc4_state->requested_output_format; ++ memcpy(&vc4_hdmi->saved_adjusted_mode, ++ &crtc_state->adjusted_mode, ++ sizeof(vc4_hdmi->saved_adjusted_mode)); + mutex_unlock(&vc4_hdmi->mutex); + } + +@@ -1950,9 +2034,6 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, case VC4_HDMI_OUTPUT_RGB: drm_dbg(dev, "RGB Format, checking the constraints.\n"); @@ -91578,7 +94665,34 @@ index 4626fe9aac56..e42b431c29af 100644 if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) { drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); return false; -@@ -2118,7 +2157,7 @@ vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, +@@ -2084,6 +2165,26 @@ vc4_hdmi_encoder_compute_format(const struct vc4_hdmi *vc4_hdmi, + const struct drm_display_info *info = &connector->display_info; + unsigned int format; + ++ if (vc4_state->requested_output_format != VC4_HDMI_OUTPUT_AUTO) { ++ drm_dbg(dev, "Trying with user requested output %u\n", ++ vc4_state->requested_output_format); ++ ++ format = vc4_state->requested_output_format; ++ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, ++ format, bpc)) { ++ int ret; ++ ++ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, ++ mode, bpc, format); ++ if (!ret) { ++ vc4_state->output_format = format; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++ } ++ + drm_dbg(dev, "Trying with an RGB output\n"); + + format = VC4_HDMI_OUTPUT_RGB; +@@ -2124,7 +2225,7 @@ vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, { struct drm_device *dev = vc4_hdmi->connector.dev; struct drm_connector_state *conn_state = &vc4_state->base; @@ -91587,7 +94701,18 @@ index 4626fe9aac56..e42b431c29af 100644 unsigned int bpc; int ret; -@@ -2386,7 +2425,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) +@@ -2170,7 +2271,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + unsigned long long tmds_bit_rate; + int ret; + +- if (vc4_hdmi->variant->unsupported_odd_h_timings) { ++ if (vc4_hdmi->variant->unsupported_odd_h_timings || ++ (vc4_hdmi->variant->unsupported_int_odd_h_timings && ++ (mode->flags & DRM_MODE_FLAG_INTERLACE))) { + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { + /* Only try to fixup DBLCLK modes to get 480i and 576i + * working. +@@ -2392,7 +2495,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) } if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { @@ -91596,7 +94721,7 @@ index 4626fe9aac56..e42b431c29af 100644 goto out_dev_exit; } -@@ -2513,6 +2552,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, +@@ -2519,6 +2622,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); struct drm_device *drm = vc4_hdmi->connector.dev; @@ -91604,7 +94729,7 @@ index 4626fe9aac56..e42b431c29af 100644 struct drm_encoder *encoder = &vc4_hdmi->encoder.base; unsigned int sample_rate = params->sample_rate; unsigned int channels = params->channels; -@@ -2571,11 +2611,24 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, +@@ -2577,11 +2681,24 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, VC4_HDMI_AUDIO_PACKET_CEA_MASK); /* Set the MAI threshold */ @@ -91634,7 +94759,7 @@ index 4626fe9aac56..e42b431c29af 100644 HDMI_WRITE(HDMI_MAI_CONFIG, VC4_HDMI_MAI_CONFIG_BIT_REVERSE | -@@ -2652,8 +2705,23 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data, +@@ -2658,8 +2775,23 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data, return 0; } @@ -91658,7 +94783,7 @@ index 4626fe9aac56..e42b431c29af 100644 .prepare = vc4_hdmi_audio_prepare, .audio_shutdown = vc4_hdmi_audio_shutdown, .audio_startup = vc4_hdmi_audio_startup, -@@ -2673,6 +2741,22 @@ static void vc4_hdmi_audio_codec_release(void *ptr) +@@ -2679,6 +2811,22 @@ static void vc4_hdmi_audio_codec_release(void *ptr) vc4_hdmi->audio.codec_pdev = NULL; } @@ -91681,7 +94806,7 @@ index 4626fe9aac56..e42b431c29af 100644 static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) { const struct vc4_hdmi_register *mai_data = -@@ -2681,7 +2765,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) +@@ -2687,7 +2835,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) struct snd_soc_card *card = &vc4_hdmi->audio.card; struct device *dev = &vc4_hdmi->pdev->dev; struct platform_device *codec_pdev; @@ -91690,7 +94815,7 @@ index 4626fe9aac56..e42b431c29af 100644 int index, len; int ret; -@@ -2717,20 +2801,15 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) +@@ -2723,22 +2871,18 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) } /* @@ -91705,16 +94830,19 @@ index 4626fe9aac56..e42b431c29af 100644 /* Before BCM2711, we don't have a named register range */ if (index < 0) index = 1; -+ iomem = platform_get_resource(vc4_hdmi->pdev, IORESOURCE_MEM, index); - addr = of_get_address(dev->of_node, index, NULL, NULL); -- +- if (!addr) ++ iomem = platform_get_resource(vc4_hdmi->pdev, IORESOURCE_MEM, index); ++ if (!iomem) + return -EINVAL; + - vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset; + vc4_hdmi->audio.dma_data.addr = iomem->start + mai_data->offset; vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; vc4_hdmi->audio.dma_data.maxburst = 2; -@@ -2800,6 +2879,8 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) +@@ -2808,6 +2952,8 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) dai_link->codecs->name = dev_name(&codec_pdev->dev); dai_link->platforms->name = dev_name(dev); @@ -91723,7 +94851,7 @@ index 4626fe9aac56..e42b431c29af 100644 card->dai_link = dai_link; card->num_links = 1; card->name = vc4_hdmi->variant->card_name; -@@ -2829,7 +2910,7 @@ static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv) +@@ -2837,7 +2983,7 @@ static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv) struct drm_connector *connector = &vc4_hdmi->connector; struct drm_device *dev = connector->dev; @@ -91732,15 +94860,17 @@ index 4626fe9aac56..e42b431c29af 100644 drm_connector_helper_hpd_irq_event(connector); return IRQ_HANDLED; -@@ -3571,6 +3652,7 @@ static int vc4_hdmi_runtime_suspend(struct device *dev) +@@ -3579,6 +3725,9 @@ static int vc4_hdmi_runtime_suspend(struct device *dev) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + clk_disable_unprepare(vc4_hdmi->audio_clock); ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(vc4_hdmi->hsm_clock, 0); clk_disable_unprepare(vc4_hdmi->hsm_clock); return 0; -@@ -3603,6 +3685,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev) +@@ -3611,6 +3760,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev) goto err_disable_clk; } @@ -91751,7 +94881,7 @@ index 4626fe9aac56..e42b431c29af 100644 if (vc4_hdmi->variant->reset) vc4_hdmi->variant->reset(vc4_hdmi); -@@ -3655,6 +3741,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) +@@ -3663,6 +3816,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; @@ -91760,7 +94890,7 @@ index 4626fe9aac56..e42b431c29af 100644 spin_lock_init(&vc4_hdmi->hw_lock); INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); -@@ -3723,7 +3811,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) +@@ -3731,7 +3886,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) return ret; if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || @@ -91771,7 +94901,7 @@ index 4626fe9aac56..e42b431c29af 100644 HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) { clk_prepare_enable(vc4_hdmi->pixel_clock); clk_prepare_enable(vc4_hdmi->hsm_clock); -@@ -3765,8 +3855,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) +@@ -3773,8 +3930,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) return ret; } @@ -91788,7 +94918,23 @@ index 4626fe9aac56..e42b431c29af 100644 }; static int vc4_hdmi_dev_probe(struct platform_device *pdev) -@@ -3857,10 +3955,66 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { +@@ -3821,6 +3986,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = true, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -3850,6 +4016,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { + PHY_LANE_2, + }, + .unsupported_odd_h_timings = true, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, +@@ -3865,10 +4032,68 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { .hp_detect = vc5_hdmi_hp_detect, }; @@ -91806,6 +94952,7 @@ index 4626fe9aac56..e42b431c29af 100644 + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = false, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, @@ -91833,6 +94980,7 @@ index 4626fe9aac56..e42b431c29af 100644 + PHY_LANE_CK, + }, + .unsupported_odd_h_timings = false, ++ .unsupported_int_odd_h_timings = true, + .external_irq_controller = true, + + .init_resources = vc5_hdmi_init_resources, @@ -91856,7 +95004,7 @@ index 4626fe9aac56..e42b431c29af 100644 }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h -index 934d5d61485a..b4212dad23d8 100644 +index 934d5d61485a..681827a59e84 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -2,8 +2,10 @@ @@ -91870,10 +95018,42 @@ index 934d5d61485a..b4212dad23d8 100644 #include #include "vc4_drv.h" -@@ -228,6 +230,31 @@ struct vc4_hdmi { +@@ -47,6 +49,10 @@ struct vc4_hdmi_variant { + + /* The BCM2711 cannot deal with odd horizontal pixel timings */ + bool unsupported_odd_h_timings; ++ /* The BCM2712 can handle odd horizontal pixel timings, but not in ++ * interlaced modes ++ */ ++ bool unsupported_int_odd_h_timings; + + /* + * The BCM2711 CEC/hotplug IRQ controller is shared between the +@@ -111,6 +117,7 @@ struct vc4_hdmi_audio { + }; + + enum vc4_hdmi_output_format { ++ VC4_HDMI_OUTPUT_AUTO, + VC4_HDMI_OUTPUT_RGB, + VC4_HDMI_OUTPUT_YUV422, + VC4_HDMI_OUTPUT_YUV444, +@@ -136,6 +143,7 @@ struct vc4_hdmi { + struct delayed_work scrambling_work; + + struct drm_property *broadcast_rgb_property; ++ struct drm_property *output_format_property; + + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; +@@ -228,6 +236,36 @@ struct vc4_hdmi { * for use outside of KMS hooks. Protected by @mutex. */ enum vc4_hdmi_output_format output_format; ++ /** ++ * @requested_output_format: Copy of @vc4_connector_state.requested_output_format ++ * for use outside of KMS hooks. Protected by @mutex. ++ */ ++ enum vc4_hdmi_output_format requested_output_format; + + /** + * @plugged_cb: Callback provided by hdmi-codec to indicate that an @@ -91902,7 +95082,15 @@ index 934d5d61485a..b4212dad23d8 100644 }; #define connector_to_vc4_hdmi(_connector) \ -@@ -263,4 +290,8 @@ void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); +@@ -246,6 +284,7 @@ struct vc4_hdmi_connector_state { + unsigned int output_bpc; + enum vc4_hdmi_output_format output_format; + enum vc4_hdmi_broadcast_rgb broadcast_rgb; ++ enum vc4_hdmi_output_format requested_output_format; + }; + + #define conn_state_to_vc4_hdmi_conn_state(_state) \ +@@ -263,4 +302,8 @@ void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); @@ -91912,10 +95100,10 @@ index 934d5d61485a..b4212dad23d8 100644 + #endif /* _VC4_HDMI_H_ */ diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c -index ec24999bf96d..0d5562714832 100644 +index ec24999bf96d..83801c268425 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c -@@ -125,6 +125,48 @@ +@@ -125,6 +125,49 @@ #define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 #define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) @@ -91931,6 +95119,7 @@ index ec24999bf96d..0d5562714832 100644 +#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFCLK_SEL_CMOS BIT(13) +#define VC6_HDMI_TX_PHY_PLL_REFCLK_REFFRQ_MASK VC4_MASK(9, 0) + ++#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_BYPASS_EN BIT(4) +#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_CLK0_SEL_MASK VC4_MASK(3, 2) +#define VC6_HDMI_TX_PHY_PLL_POST_KDIV_KDIV_MASK VC4_MASK(1, 0) + @@ -91964,7 +95153,7 @@ index ec24999bf96d..0d5562714832 100644 #define OSCILLATOR_FREQUENCY 54000000 void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, -@@ -558,3 +600,601 @@ void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) +@@ -558,3 +601,607 @@ void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } @@ -92315,6 +95504,7 @@ index ec24999bf96d..0d5562714832 100644 + + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); + HDMI_WRITE(HDMI_TX_PHY_POWERUP_CTL, 0); ++ HDMI_WRITE(HDMI_TX_PHY_PLL_POST_KDIV, VC6_HDMI_TX_PHY_PLL_POST_KDIV_BYPASS_EN); +} + +void vc6_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, @@ -92565,6 +95755,11 @@ index ec24999bf96d..0d5562714832 100644 + +void vc6_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) +{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); ++ vc6_hdmi_reset_phy(vc4_hdmi); ++ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); +} diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index b04b2fc8d831..59bfd69f54d9 100644 @@ -92822,7 +96017,7 @@ index b04b2fc8d831..59bfd69f54d9 100644 writel(value, base + field->offset); } diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c -index 04af672caacb..e9b0a21e5707 100644 +index 04af672caacb..02a9bb43035d 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -33,7 +33,7 @@ @@ -93045,7 +96240,7 @@ index 04af672caacb..e9b0a21e5707 100644 dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); drm_printf(&p, "dlist: %02d: 0x%08x\n", j, dlist_word); -@@ -143,6 +327,115 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) +@@ -143,6 +327,157 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) return 0; } @@ -93157,11 +96352,63 @@ index 04af672caacb..e9b0a21e5707 100644 + + return 0; +} ++ ++static int vc6_hvs_debugfs_upm_allocs(struct seq_file *m, void *data) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ struct vc4_upm_refcounts *refcount; ++ unsigned int i; ++ ++ drm_printf(&p, "UPM Handles:\n"); ++ for (i = 0; i < VC4_NUM_UPM_HANDLES; i++) { ++ refcount = &hvs->upm_refcounts[i]; ++ drm_printf(&p, "handle %u: refcount %u, size %zu [%08llx + %08llx]\n", ++ i, refcount_read(&refcount->refcount), refcount->size, ++ refcount->upm.start, refcount->upm.size); ++ } ++ ++ return 0; ++} ++ ++static int vc4_hvs_debugfs_lbm_allocs(struct seq_file *m, void *data) ++{ ++ struct drm_debugfs_entry *entry = m->private; ++ struct drm_device *dev = entry->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; ++ struct drm_printer p = drm_seq_file_printer(m); ++ struct vc4_lbm_refcounts *refcount; ++ unsigned int i; ++ ++ drm_printf(&p, "LBM Handles:\n"); ++ for (i = 0; i < VC4_NUM_LBM_HANDLES; i++) { ++ refcount = &hvs->lbm_refcounts[i]; ++ drm_printf(&p, "handle %u: refcount %u, size %zu [%08llx + %08llx]\n", ++ i, refcount_read(&refcount->refcount), refcount->size, ++ refcount->lbm.start, refcount->lbm.size); ++ } ++ ++ return 0; ++} + /* The filter kernel is composed of dwords each containing 3 9-bit * signed integers packed next to each other. */ -@@ -213,12 +506,15 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, +@@ -176,6 +511,9 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) + static const u32 mitchell_netravali_1_3_1_3_kernel[] = + VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18, + 50, 82, 119, 155, 187, 213, 227); ++static const u32 nearest_neighbour_kernel[] = ++ VC4_LINEAR_PHASE_KERNEL(0, 0, 0, 0, 0, 0, 0, 0, ++ 1, 1, 1, 1, 255, 255, 255, 255); + + static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, + struct drm_mm_node *space, +@@ -213,12 +551,15 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, static void vc4_hvs_lut_load(struct vc4_hvs *hvs, struct vc4_crtc *vc4_crtc) { @@ -93178,7 +96425,7 @@ index 04af672caacb..e9b0a21e5707 100644 if (!drm_dev_enter(drm, &idx)) return; -@@ -243,7 +539,8 @@ static void vc4_hvs_lut_load(struct vc4_hvs *hvs, +@@ -243,7 +584,8 @@ static void vc4_hvs_lut_load(struct vc4_hvs *hvs, static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, struct vc4_crtc *vc4_crtc) { @@ -93188,7 +96435,7 @@ index 04af672caacb..e9b0a21e5707 100644 struct drm_color_lut *lut = crtc_state->gamma_lut->data; u32 length = drm_color_lut_size(crtc_state->gamma_lut); u32 i; -@@ -257,233 +554,769 @@ static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, +@@ -257,218 +599,740 @@ static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, vc4_hvs_lut_load(hvs, vc4_crtc); } @@ -93586,30 +96833,17 @@ index 04af672caacb..e9b0a21e5707 100644 - /* The pixelvalve can only feed one encoder (and encoders are - * 1:1 with connectors.) -- */ -- if (hweight32(crtc_state->connector_mask) > 1) -- return -EINVAL; + spin_lock_irqsave(&hvs->mm_lock, flags); - -- drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) -- dlist_count += vc4_plane_dlist_size(plane_state); ++ + if (!list_empty(&hvs->stale_dlist_entries)) + queue_work(system_unbound_wq, &hvs->free_dlist_work); - -- dlist_count++; /* Account for SCALER_CTL0_END. */ ++ + if (list_empty(&hvs->stale_dlist_entries)) + vc4_hvs_irq_clear_eof(hvs, channel); - -- spin_lock_irqsave(&vc4->hvs->mm_lock, flags); -- ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm, -- dlist_count); -- spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); -- if (ret) -- return ret; ++ + spin_unlock_irqrestore(&hvs->mm_lock, flags); +} - -- return 0; ++ +/* + * Frame counts are essentially sequence numbers over 6 bits, and we + * thus can use sequence number arithmetic and follow the RFC1982 to @@ -93618,25 +96852,15 @@ index 04af672caacb..e9b0a21e5707 100644 +static bool vc4_hvs_frcnt_lte(u8 cnt1, u8 cnt2) +{ + return (s8)((cnt1 << 2) - (cnt2 << 2)) <= 0; - } - --static void vc4_hvs_install_dlist(struct drm_crtc *crtc) ++} ++ +bool vc4_hvs_check_channel_active(struct vc4_hvs *hvs, unsigned int fifo) - { -- struct drm_device *dev = crtc->dev; -- struct vc4_dev *vc4 = to_vc4_dev(dev); -- struct vc4_hvs *hvs = vc4->hvs; -- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); ++{ + struct vc4_dev *vc4 = hvs->vc4; + struct drm_device *drm = &vc4->base; + bool enabled = false; - int idx; - -- if (!drm_dev_enter(dev, &idx)) -- return; -- -- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), -- vc4_state->mm.start); ++ int idx; ++ + WARN_ON_ONCE(vc4->gen > VC4_GEN_6); + + if (!drm_dev_enter(drm, &idx)) @@ -94061,17 +97285,16 @@ index 04af672caacb..e9b0a21e5707 100644 + struct drm_plane *plane; + const struct drm_plane_state *plane_state; + u32 dlist_count = 0; -+ u32 lbm_count = 0; + + /* The pixelvalve can only feed one encoder (and encoders are + * 1:1 with connectors.) -+ */ -+ if (hweight32(crtc_state->connector_mask) > 1) -+ return -EINVAL; -+ + */ + if (hweight32(crtc_state->connector_mask) > 1) + return -EINVAL; + +- drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) +- dlist_count += vc4_plane_dlist_size(plane_state); + drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { -+ const struct vc4_plane_state *vc4_plane_state = -+ to_vc4_plane_state(plane_state); + u32 plane_dlist_count = vc4_plane_dlist_size(plane_state); + + drm_dbg_driver(dev, "[CRTC:%d:%s] Found [PLANE:%d:%s] with DLIST size: %u\n", @@ -94080,36 +97303,36 @@ index 04af672caacb..e9b0a21e5707 100644 + plane_dlist_count); + + dlist_count += plane_dlist_count; -+ lbm_count += vc4_plane_state->lbm_size; + } -+ -+ dlist_count++; /* Account for SCALER_CTL0_END. */ -+ + + dlist_count++; /* Account for SCALER_CTL0_END. */ + +- spin_lock_irqsave(&vc4->hvs->mm_lock, flags); +- ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm, +- dlist_count); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); +- if (ret) +- return ret; + drm_dbg_driver(dev, "[CRTC:%d:%s] Allocating DLIST block with size: %u\n", + crtc->base.id, crtc->name, dlist_count); -+ + +- return 0; + alloc = vc4_hvs_alloc_dlist_entry(vc4->hvs, vc4_state->assigned_channel, dlist_count); + if (IS_ERR(alloc)) + return PTR_ERR(alloc); + + vc4_state->mm = alloc; + -+ /* FIXME: Check total lbm allocation here */ -+ + return vc4_hvs_gamma_check(crtc, state); -+} -+ -+static void vc4_hvs_install_dlist(struct drm_crtc *crtc) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct vc4_dev *vc4 = to_vc4_dev(dev); -+ struct vc4_hvs *hvs = vc4->hvs; -+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); -+ int idx; -+ -+ if (!drm_dev_enter(dev, &idx)) -+ return; -+ + } + + static void vc4_hvs_install_dlist(struct drm_crtc *crtc) +@@ -482,8 +1346,16 @@ static void vc4_hvs_install_dlist(struct drm_crtc *crtc) + if (!drm_dev_enter(dev, &idx)) + return; + +- HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), +- vc4_state->mm.start); + WARN_ON(!vc4_state->mm); + vc4_state->mm->dlist_programmed = true; + @@ -94123,7 +97346,7 @@ index 04af672caacb..e9b0a21e5707 100644 drm_dev_exit(idx); } -@@ -510,8 +1343,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) +@@ -510,8 +1382,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -94135,7 +97358,7 @@ index 04af672caacb..e9b0a21e5707 100644 spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); } -@@ -538,7 +1373,11 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, +@@ -538,7 +1412,11 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, vc4_hvs_install_dlist(crtc); vc4_hvs_update_dlist(crtc); @@ -94148,7 +97371,7 @@ index 04af672caacb..e9b0a21e5707 100644 } void vc4_hvs_atomic_disable(struct drm_crtc *crtc, -@@ -567,13 +1406,17 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, +@@ -567,13 +1445,14 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_plane *plane; struct vc4_plane_state *vc4_plane_state; bool debug_dump_regs = false; @@ -94157,10 +97380,7 @@ index 04af672caacb..e9b0a21e5707 100644 - u32 __iomem *dlist_next = dlist_start; + bool enable_bg_fill = true; + u32 __iomem *dlist_start, *dlist_next; -+ unsigned long irqflags; unsigned int zpos = 0; -+ u32 lbm_offset = 0; -+ u32 lbm_size = 0; bool found = false; int idx; @@ -94169,71 +97389,16 @@ index 04af672caacb..e9b0a21e5707 100644 if (!drm_dev_enter(dev, &idx)) { vc4_crtc_send_vblank(crtc); return; -@@ -587,6 +1430,38 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, +@@ -587,6 +1466,9 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, vc4_hvs_dump_state(hvs); } -+ drm_atomic_crtc_for_each_plane(plane, crtc) { -+ vc4_plane_state = to_vc4_plane_state(plane->state); -+ lbm_size += vc4_plane_state->lbm_size; -+ } -+ -+ if (drm_mm_node_allocated(&vc4_crtc->lbm)) { -+ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); -+ drm_mm_remove_node(&vc4_crtc->lbm); -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); -+ } -+ -+ if (lbm_size) { -+ int ret; -+ -+ spin_lock_irqsave(&vc4_crtc->irq_lock, irqflags); -+ ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, -+ &vc4_crtc->lbm, -+ lbm_size, 1, -+ 0, 0); -+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, irqflags); -+ -+ if (ret) { -+ pr_err("Failed to allocate LBM ret %d\n", ret); -+ return; -+ } -+ } -+ -+ lbm_offset = vc4_crtc->lbm.start; -+ + dlist_start = vc4->hvs->dlist + vc4_state->mm->mm_node.start; + dlist_next = dlist_start; + /* Copy all the active planes' dlist contents to the hardware dlist. */ do { found = false; -@@ -595,6 +1470,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, - if (plane->state->normalized_zpos != zpos) - continue; - -+ vc4_plane_state = to_vc4_plane_state(plane->state); -+ - /* Is this the first active plane? */ - if (dlist_next == dlist_start) { - /* We need to enable background fill when a plane -@@ -605,10 +1482,15 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, - * already needs it or all planes on top blend from - * the first or a lower plane. - */ -- vc4_plane_state = to_vc4_plane_state(plane->state); - enable_bg_fill = vc4_plane_state->needs_bg_fill; - } - -+ if (vc4_plane_state->lbm_size) { -+ vc4_plane_state->dlist[vc4_plane_state->lbm_offset] = -+ lbm_offset; -+ lbm_offset += vc4_plane_state->lbm_size; -+ } -+ - dlist_next += vc4_plane_write_dlist(plane, dlist_next); - - found = true; @@ -620,15 +1502,29 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, writel(SCALER_CTL0_END, dlist_next); dlist_next++; @@ -94355,7 +97520,7 @@ index 04af672caacb..e9b0a21e5707 100644 /* * NOTE: We don't need to protect the register access using * drm_dev_enter() there because the interrupt handler lifetime -@@ -738,24 +1657,54 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) +@@ -738,8 +1657,10 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) control = HVS_READ(SCALER_DISPCTRL); for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { @@ -94368,20 +97533,21 @@ index 04af672caacb..e9b0a21e5707 100644 /* Interrupt masking is not always honored, so check it here. */ if (status & SCALER_DISPSTAT_EUFLOW(channel) && control & dspeislur) { - vc4_hvs_mask_underrun(hvs, channel); - vc4_hvs_report_underrun(dev); +@@ -748,14 +1669,42 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) -- irqret = IRQ_HANDLED; -- } -+ irqret = IRQ_HANDLED; -+ } + irqret = IRQ_HANDLED; + } + + if (status & SCALER_DISPSTAT_EOF(channel)) { + vc4_hvs_schedule_dlist_sweep(hvs, channel); + irqret = IRQ_HANDLED; + } -+ } -+ + } + +- /* Clear every per-channel interrupt flag. */ +- HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | +- SCALER_DISPSTAT_IRQMASK(1) | +- SCALER_DISPSTAT_IRQMASK(2)); + /* Clear every per-channel interrupt flag. */ + HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | + SCALER_DISPSTAT_IRQMASK(1) | @@ -94408,19 +97574,14 @@ index 04af672caacb..e9b0a21e5707 100644 + + vc4_hvs_schedule_dlist_sweep(hvs, i); + return IRQ_HANDLED; - } ++ } -- /* Clear every per-channel interrupt flag. */ -- HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | -- SCALER_DISPSTAT_IRQMASK(1) | -- SCALER_DISPSTAT_IRQMASK(2)); -- - return irqret; + return IRQ_NONE; } int vc4_hvs_debugfs_init(struct drm_minor *minor) -@@ -764,136 +1713,153 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor) +@@ -764,136 +1713,164 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor) struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_hvs *hvs = vc4->hvs; @@ -94441,10 +97602,14 @@ index 04af672caacb..e9b0a21e5707 100644 + NULL); + } + -+ if (vc4->gen >= VC4_GEN_6) ++ if (vc4->gen >= VC4_GEN_6) { + drm_debugfs_add_file(drm, "hvs_dlists", vc6_hvs_debugfs_dlist, NULL); -+ else ++ drm_debugfs_add_file(drm, "hvs_upm", vc6_hvs_debugfs_upm_allocs, NULL); ++ } else { + drm_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL); ++ } ++ ++ drm_debugfs_add_file(drm, "hvs_lbm", vc4_hvs_debugfs_lbm_allocs, NULL); drm_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, NULL); @@ -94465,6 +97630,7 @@ index 04af672caacb..e9b0a21e5707 100644 + unsigned int dlist_start; + size_t dlist_size; + size_t lbm_size; ++ unsigned int i; hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL); if (!hvs) @@ -94512,6 +97678,11 @@ index 04af672caacb..e9b0a21e5707 100644 + else + dlist_size = 4096; + ++ for (i = 0; i < VC4_NUM_UPM_HANDLES; i++) { ++ refcount_set(&hvs->upm_refcounts[i].refcount, 0); ++ hvs->upm_refcounts[i].hvs = hvs; ++ } ++ + break; + + default: @@ -94534,7 +97705,7 @@ index 04af672caacb..e9b0a21e5707 100644 - else - /* 60k words of 4x12-bit pixels */ - drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024); -- + - vc4->hvs = hvs; - - return hvs; @@ -94553,7 +97724,7 @@ index 04af672caacb..e9b0a21e5707 100644 - hvs = __vc4_hvs_alloc(vc4, NULL); - if (IS_ERR(hvs)) - return PTR_ERR(hvs); - +- - hvs->regs = vc4_ioremap_regs(pdev, 0); - if (IS_ERR(hvs->regs)) - return PTR_ERR(hvs->regs); @@ -94596,6 +97767,7 @@ index 04af672caacb..e9b0a21e5707 100644 - if (!firmware) - return -EPROBE_DEFER; + drm_mm_init(&hvs->lbm_mm, 0, lbm_size); ++ ida_init(&hvs->lbm_handles); - hvs->core_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(hvs->core_clk)) { @@ -94658,7 +97830,7 @@ index 04af672caacb..e9b0a21e5707 100644 reg = HVS_READ(SCALER_DISPECTRL); reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK; -@@ -916,13 +1882,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +@@ -916,13 +1893,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) reg | VC4_SET_FIELD(3, SCALER_DISPDITHER_DSP5_MUX)); dispctrl = HVS_READ(SCALER_DISPCTRL); @@ -94673,7 +97845,7 @@ index 04af672caacb..e9b0a21e5707 100644 dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | SCALER_DISPCTRL_SLVWREIRQ | SCALER_DISPCTRL_SLVRDEIRQ | -@@ -951,6 +1915,17 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +@@ -951,6 +1926,17 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) SCALER_DISPCTRL_SCLEIRQ); @@ -94691,7 +97863,7 @@ index 04af672caacb..e9b0a21e5707 100644 /* Set AXI panic mode. * VC4 panics when < 2 lines in FIFO. * VC5 panics when less than 1 line in the FIFO. -@@ -964,9 +1939,160 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +@@ -964,9 +1950,160 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) HVS_WRITE(SCALER_DISPCTRL, dispctrl); @@ -94854,7 +98026,7 @@ index 04af672caacb..e9b0a21e5707 100644 /* The COB is 20736 pixels, or just over 10 lines at 2048 wide. * The bottom 2048 pixels are full 32bpp RGBA (intended for the * TXP composing RGBA to memory), whilst the remainder are only -@@ -990,7 +2116,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +@@ -990,7 +2127,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) top = VC4_COB_SIZE; reg |= (top - 1) << 16; HVS_WRITE(SCALER_DISPBASE0, reg); @@ -94865,7 +98037,7 @@ index 04af672caacb..e9b0a21e5707 100644 /* The COB is 44416 pixels, or 10.8 lines at 4096 wide. * The bottom 4096 pixels are full RGBA (intended for the TXP * composing RGBA to memory), whilst the remainder are only -@@ -1016,13 +2144,182 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +@@ -1016,13 +2155,187 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) top = VC5_COB_SIZE; reg |= top << 16; HVS_WRITE(SCALER_DISPBASE0, reg); @@ -95027,14 +98199,19 @@ index 04af672caacb..e9b0a21e5707 100644 + if (ret) + return ret; + -+ /* Upload filter kernels. We only have the one for now, so we -+ * keep it around for the lifetime of the driver. ++ /* Upload filter kernels. We only have the two for now, so we ++ * keep them around for the lifetime of the driver. + */ + ret = vc4_hvs_upload_linear_kernel(hvs, + &hvs->mitchell_netravali_filter, + mitchell_netravali_1_3_1_3_kernel); + if (ret) + return ret; ++ ret = vc4_hvs_upload_linear_kernel(hvs, ++ &hvs->nearest_neighbour_filter, ++ nearest_neighbour_kernel); ++ if (ret) ++ return ret; + + ret = vc4_hvs_cob_init(hvs); if (ret) @@ -95050,15 +98227,27 @@ index 04af672caacb..e9b0a21e5707 100644 return 0; } -@@ -1046,6 +2343,7 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, +@@ -1036,6 +2349,8 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, + + if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter)) + drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter); ++ if (drm_mm_node_allocated(&vc4->hvs->nearest_neighbour_filter)) ++ drm_mm_remove_node(&vc4->hvs->nearest_neighbour_filter); + + drm_mm_for_each_node_safe(node, next, &vc4->hvs->dlist_mm) + drm_mm_remove_node(node); +@@ -1046,6 +2361,10 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, drm_mm_remove_node(node); drm_mm_takedown(&vc4->hvs->lbm_mm); ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(hvs->disp_clk, 0); + clk_disable_unprepare(hvs->disp_clk); ++ clk_set_min_rate(hvs->core_clk, 0); clk_disable_unprepare(hvs->core_clk); vc4->hvs = NULL; -@@ -1068,6 +2366,8 @@ static void vc4_hvs_dev_remove(struct platform_device *pdev) +@@ -1068,6 +2387,8 @@ static void vc4_hvs_dev_remove(struct platform_device *pdev) static const struct of_device_id vc4_hvs_dt_match[] = { { .compatible = "brcm,bcm2711-hvs" }, @@ -95117,7 +98306,7 @@ index 563b3dfeb9b9..8581cc212a12 100644 /* Acknowledge any stale IRQs. */ diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c -index 5495f2a94fa9..ea66914ed5ea 100644 +index 5495f2a94fa9..eb57a1b96ab1 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -138,6 +138,11 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) @@ -95132,7 +98321,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 if (ctm_state->fifo) { HVS_WRITE(SCALER_OLEDCOEF2, VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), -@@ -213,6 +218,8 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, +@@ -213,11 +218,13 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, struct drm_crtc *crtc; unsigned int i; @@ -95141,7 +98330,42 @@ index 5495f2a94fa9..ea66914ed5ea 100644 for_each_new_crtc_in_state(state, crtc, crtc_state, i) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); -@@ -256,6 +263,8 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, + u32 dispctrl; +- u32 dsp3_mux; ++ u32 dsp3_mux_pri; + + if (!crtc_state->active) + continue; +@@ -234,15 +241,22 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, + * enabled. In this case, FIFO 2 is directly accessed by the + * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 + * route. ++ * ++ * TXP can also run with a lower panic level than a live display, ++ * as it doesn't have the same real-time constraint. + */ +- if (vc4_crtc->feeds_txp) +- dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); +- else +- dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ if (vc4_crtc->feeds_txp) { ++ dsp3_mux_pri = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); ++ dsp3_mux_pri |= VC4_SET_FIELD(0, SCALER_DISPCTRL_PANIC2); ++ } else { ++ dsp3_mux_pri = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); ++ dsp3_mux_pri |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2); ++ } + + dispctrl = HVS_READ(SCALER_DISPCTRL) & +- ~SCALER_DISPCTRL_DSP3_MUX_MASK; +- HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); ++ ~(SCALER_DISPCTRL_DSP3_MUX_MASK | ++ SCALER_DISPCTRL_PANIC2_MASK); ++ HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux_pri); + } + } + +@@ -256,6 +270,8 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, unsigned int i; u32 reg; @@ -95150,7 +98374,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 for_each_new_crtc_in_state(state, crtc, crtc_state, i) { struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -@@ -320,17 +329,59 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, +@@ -320,17 +336,59 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, } } @@ -95213,7 +98437,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 old_hvs_state = vc4_hvs_get_old_global_state(state); if (WARN_ON(IS_ERR(old_hvs_state))) -@@ -340,14 +391,23 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -340,14 +398,23 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) if (WARN_ON(IS_ERR(new_hvs_state))) return; @@ -95228,22 +98452,22 @@ index 5495f2a94fa9..ea66914ed5ea 100644 - continue; + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + struct vc4_crtc_state *vc4_crtc_state; - -- vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); -- vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); ++ + if (vc4->firmware_kms) + continue; + + if (!new_crtc_state->commit) + continue; -+ + +- vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); +- vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); + vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); + vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel); + } } for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) { -@@ -369,7 +429,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -369,7 +436,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) old_hvs_state->fifo_state[channel].pending_commit = NULL; } @@ -95252,7 +98476,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 unsigned long state_rate = max(old_hvs_state->core_clock_rate, new_hvs_state->core_clock_rate); unsigned long core_rate = clamp_t(unsigned long, state_rate, -@@ -382,16 +442,33 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -382,16 +449,33 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) * modeset. */ WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); @@ -95264,11 +98488,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 - vc4_ctm_commit(vc4, state); + if (vc4->gen <= VC4_GEN_5) + vc4_ctm_commit(vc4, state); - -- if (vc4->is_vc5) -- vc5_hvs_pv_muxing_commit(vc4, state); -- else -- vc4_hvs_pv_muxing_commit(vc4, state); ++ + if (!vc4->firmware_kms) { + switch (vc4->gen) { + case VC4_GEN_4: @@ -95278,7 +98498,11 @@ index 5495f2a94fa9..ea66914ed5ea 100644 + case VC4_GEN_5: + vc5_hvs_pv_muxing_commit(vc4, state); + break; -+ + +- if (vc4->is_vc5) +- vc5_hvs_pv_muxing_commit(vc4, state); +- else +- vc4_hvs_pv_muxing_commit(vc4, state); + case VC4_GEN_6: + vc6_hvs_pv_muxing_commit(vc4, state); + break; @@ -95291,7 +98515,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 drm_atomic_helper_commit_planes(dev, state, DRM_PLANE_COMMIT_ACTIVE_ONLY); -@@ -406,7 +483,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -406,7 +490,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_cleanup_planes(dev, state); @@ -95300,7 +98524,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 unsigned long core_rate = min_t(unsigned long, hvs->max_core_rate, new_hvs_state->core_clock_rate); -@@ -418,6 +495,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -418,6 +502,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) * requirements. */ WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); @@ -95308,7 +98532,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 drm_dbg(dev, "Core clock actual rate: %lu Hz\n", clk_get_rate(hvs->core_clk)); -@@ -426,11 +504,21 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) +@@ -426,11 +511,21 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) static int vc4_atomic_commit_setup(struct drm_atomic_state *state) { @@ -95330,7 +98554,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 hvs_state = vc4_hvs_get_new_global_state(state); if (WARN_ON(IS_ERR(hvs_state))) return PTR_ERR(hvs_state); -@@ -461,7 +549,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, +@@ -461,7 +556,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_mode_fb_cmd2 mode_cmd_local; @@ -95339,7 +98563,38 @@ index 5495f2a94fa9..ea66914ed5ea 100644 return ERR_PTR(-ENODEV); /* If the user didn't specify a modifier, use the -@@ -799,6 +887,7 @@ static int cmp_vc4_crtc_hvs_output(const void *a, const void *b) +@@ -586,17 +681,26 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state) + for_each_oldnew_plane_in_state(state, plane, old_plane_state, + new_plane_state, i) { + struct vc4_plane_state *vc4_plane_state; ++ struct vc4_crtc *vc4_crtc; + + if (old_plane_state->fb && old_plane_state->crtc) { + vc4_plane_state = to_vc4_plane_state(old_plane_state); +- load_state->membus_load -= vc4_plane_state->membus_load; +- load_state->hvs_load -= vc4_plane_state->hvs_load; ++ vc4_crtc = to_vc4_crtc(old_plane_state->crtc); ++ ++ if (!vc4_crtc->feeds_txp) { ++ load_state->membus_load -= vc4_plane_state->membus_load; ++ load_state->hvs_load -= vc4_plane_state->hvs_load; ++ } + } + + if (new_plane_state->fb && new_plane_state->crtc) { + vc4_plane_state = to_vc4_plane_state(new_plane_state); +- load_state->membus_load += vc4_plane_state->membus_load; +- load_state->hvs_load += vc4_plane_state->hvs_load; ++ vc4_crtc = to_vc4_crtc(new_plane_state->crtc); ++ ++ if (!vc4_crtc->feeds_txp) { ++ load_state->membus_load += vc4_plane_state->membus_load; ++ load_state->hvs_load += vc4_plane_state->hvs_load; ++ } + } + } + +@@ -799,6 +903,7 @@ static int cmp_vc4_crtc_hvs_output(const void *a, const void *b) static int vc4_pv_muxing_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -95347,7 +98602,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 struct vc4_hvs_state *hvs_new_state; struct drm_crtc **sorted_crtcs; struct drm_crtc *crtc; -@@ -806,6 +895,9 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, +@@ -806,6 +911,9 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, unsigned int i; int ret; @@ -95357,7 +98612,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 hvs_new_state = vc4_hvs_get_global_state(state); if (IS_ERR(hvs_new_state)) return PTR_ERR(hvs_new_state); -@@ -1040,7 +1132,7 @@ int vc4_kms_load(struct drm_device *dev) +@@ -1040,7 +1148,7 @@ int vc4_kms_load(struct drm_device *dev) * the BCM2711, but the load tracker computations are used for * the core clock rate calculation. */ @@ -95366,7 +98621,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 /* Start with the load tracker enabled. Can be * disabled through the debugfs load_tracker file. */ -@@ -1056,7 +1148,10 @@ int vc4_kms_load(struct drm_device *dev) +@@ -1056,7 +1164,10 @@ int vc4_kms_load(struct drm_device *dev) return ret; } @@ -95378,7 +98633,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 dev->mode_config.max_width = 7680; dev->mode_config.max_height = 7680; } else { -@@ -1064,7 +1159,7 @@ int vc4_kms_load(struct drm_device *dev) +@@ -1064,7 +1175,7 @@ int vc4_kms_load(struct drm_device *dev) dev->mode_config.max_height = 2048; } @@ -95388,7 +98643,7 @@ index 5495f2a94fa9..ea66914ed5ea 100644 dev->mode_config.preferred_depth = 24; dev->mode_config.async_page_flip = true; diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c -index c4ac2c946238..4cd3643c3ba7 100644 +index c00a5cc2316d..75ff2f748235 100644 --- a/drivers/gpu/drm/vc4/vc4_perfmon.c +++ b/drivers/gpu/drm/vc4/vc4_perfmon.c @@ -23,7 +23,7 @@ void vc4_perfmon_get(struct vc4_perfmon *perfmon) @@ -95445,7 +98700,7 @@ index c4ac2c946238..4cd3643c3ba7 100644 return; mutex_init(&vc4file->perfmon.lock); -@@ -126,7 +126,7 @@ void vc4_perfmon_close_file(struct vc4_file *vc4file) +@@ -131,7 +131,7 @@ void vc4_perfmon_close_file(struct vc4_file *vc4file) { struct vc4_dev *vc4 = vc4file->dev; @@ -95454,7 +98709,7 @@ index c4ac2c946238..4cd3643c3ba7 100644 return; mutex_lock(&vc4file->perfmon.lock); -@@ -146,7 +146,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, +@@ -151,7 +151,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, unsigned int i; int ret; @@ -95463,7 +98718,7 @@ index c4ac2c946238..4cd3643c3ba7 100644 return -ENODEV; if (!vc4->v3d) { -@@ -200,7 +200,7 @@ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, +@@ -205,7 +205,7 @@ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, struct drm_vc4_perfmon_destroy *req = data; struct vc4_perfmon *perfmon; @@ -95472,7 +98727,7 @@ index c4ac2c946238..4cd3643c3ba7 100644 return -ENODEV; if (!vc4->v3d) { -@@ -228,7 +228,7 @@ int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, +@@ -233,7 +233,7 @@ int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, struct vc4_perfmon *perfmon; int ret; @@ -95482,7 +98737,7 @@ index c4ac2c946238..4cd3643c3ba7 100644 if (!vc4->v3d) { diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c -index 5948e34f7f81..2d1039aa2dcf 100644 +index 5948e34f7f81..acedc1b89f2e 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -109,6 +109,18 @@ static const struct hvs_format { @@ -95516,37 +98771,71 @@ index 5948e34f7f81..2d1039aa2dcf 100644 return VC4_SCALING_PPF; else return VC4_SCALING_TPZ; -@@ -264,9 +276,10 @@ static bool plane_enabled(struct drm_plane_state *state) +@@ -264,9 +276,12 @@ static bool plane_enabled(struct drm_plane_state *state) return state->fb && !WARN_ON(!state->crtc); } -static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) +struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) { ++ struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ struct vc4_hvs *hvs = vc4->hvs; struct vc4_plane_state *vc4_state; + unsigned int i; if (WARN_ON(!plane->state)) return NULL; -@@ -275,7 +288,11 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane +@@ -275,7 +290,13 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane if (!vc4_state) return NULL; - memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); -+ memset(&vc4_state->upm, 0, sizeof(vc4_state->upm)); -+ -+ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) -+ vc4_state->upm_handle[i] = 0; ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { ++ if (vc4_state->upm_handle[i]) ++ refcount_inc(&hvs->upm_refcounts[vc4_state->upm_handle[i]].refcount); ++ } ++ if (vc4_state->lbm_handle) ++ refcount_inc(&hvs->lbm_refcounts[vc4_state->lbm_handle].refcount); + vc4_state->dlist_initialized = 0; __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); -@@ -294,18 +311,26 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane +@@ -294,18 +315,63 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane return &vc4_state->base; } -static void vc4_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) ++void vc4_plane_release_lbm_ida(struct vc4_hvs *hvs, unsigned int lbm_handle) ++{ ++ struct vc4_lbm_refcounts *refcount = &hvs->lbm_refcounts[lbm_handle]; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ drm_mm_remove_node(&refcount->lbm); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ refcount->lbm.start = 0; ++ refcount->lbm.size = 0; ++ refcount->size = 0; ++ ++ ida_free(&hvs->lbm_handles, lbm_handle); ++} ++ ++void vc4_plane_release_upm_ida(struct vc4_hvs *hvs, unsigned int upm_handle) ++{ ++ struct vc4_upm_refcounts *refcount = &hvs->upm_refcounts[upm_handle]; ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ drm_mm_remove_node(&refcount->upm); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ refcount->upm.start = 0; ++ refcount->upm.size = 0; ++ refcount->size = 0; ++ ++ ida_free(&hvs->upm_handles, upm_handle); ++} ++ +void vc4_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) { @@ -95556,25 +98845,33 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + unsigned int i; - if (drm_mm_node_allocated(&vc4_state->lbm)) { +- unsigned long irqflags; ++ if (vc4_state->lbm_handle) { ++ struct vc4_lbm_refcounts *refcount; ++ ++ refcount = &hvs->lbm_refcounts[vc4_state->lbm_handle]; ++ ++ if (refcount_dec_and_test(&refcount->refcount)) ++ vc4_plane_release_lbm_ida(hvs, vc4_state->lbm_handle); ++ } ++ + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { - unsigned long irqflags; ++ struct vc4_upm_refcounts *refcount; - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); - drm_mm_remove_node(&vc4_state->lbm); - spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); -+ if (!drm_mm_node_allocated(&vc4_state->upm[i])) ++ if (!vc4_state->upm_handle[i]) + continue; + -+ spin_lock_irqsave(&hvs->mm_lock, irqflags); -+ drm_mm_remove_node(&vc4_state->upm[i]); -+ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ refcount = &hvs->upm_refcounts[vc4_state->upm_handle[i]]; + -+ if (vc4_state->upm_handle[i] > 0) -+ ida_free(&hvs->upm_handles, vc4_state->upm_handle[i]); ++ if (refcount_dec_and_test(&refcount->refcount)) ++ vc4_plane_release_upm_ida(hvs, vc4_state->upm_handle[i]); } kfree(vc4_state->dlist); -@@ -314,7 +339,7 @@ static void vc4_plane_destroy_state(struct drm_plane *plane, +@@ -314,7 +380,7 @@ static void vc4_plane_destroy_state(struct drm_plane *plane, } /* Called during init to allocate the plane's atomic state. */ @@ -95583,7 +98880,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 { struct vc4_plane_state *vc4_state; -@@ -438,12 +463,11 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) +@@ -438,12 +504,11 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct drm_framebuffer *fb = state->fb; @@ -95597,7 +98894,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); -@@ -457,26 +481,21 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) +@@ -457,26 +522,21 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) if (ret) return ret; @@ -95633,7 +98930,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 ret = vc4_plane_margins_adj(state); if (ret) return ret; -@@ -510,6 +529,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) +@@ -510,6 +570,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) */ if (vc4_state->x_scaling[1] == VC4_SCALING_NONE) vc4_state->x_scaling[1] = VC4_SCALING_PPF; @@ -95646,7 +98943,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 } else { vc4_state->is_yuv = false; vc4_state->x_scaling[1] = VC4_SCALING_NONE; -@@ -521,9 +546,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) +@@ -521,9 +587,12 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) { @@ -95660,7 +98957,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* The specs note that while the reciprocal would be defined * as (1<<32)/scale, ~0 is close enough. -@@ -531,23 +559,70 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) +@@ -531,23 +600,73 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) recip = ~0 / scale; vc4_dlist_write(vc4_state, @@ -95679,7 +98976,9 @@ index 5948e34f7f81..2d1039aa2dcf 100644 +/* phase magnitude bits */ +#define PHASE_BITS 6 + -+static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel, int chroma_offset) ++static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, ++ u32 xy, int channel, int chroma_offset, ++ bool no_interpolate) { - u32 scale = (1 << 16) * src / dst; + struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); @@ -95719,6 +99018,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + phase &= SCALER_PPF_IPHASE_MASK; vc4_dlist_write(vc4_state, ++ (no_interpolate ? SCALER_PPF_NOINTERP : 0) | SCALER_PPF_AGC | VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | - VC4_SET_FIELD(0, SCALER_PPF_IPHASE)); @@ -95735,7 +99035,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); -@@ -569,7 +644,7 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) +@@ -569,7 +688,7 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ) pix_per_line = vc4_state->crtc_w; else @@ -95744,7 +99044,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 if (!vc4_state->is_yuv) { if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) -@@ -587,29 +662,159 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) +@@ -587,29 +706,161 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) } /* Align it to 64 or 128 (hvs5) bytes */ @@ -95895,20 +99195,22 @@ index 5948e34f7f81..2d1039aa2dcf 100644 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { vc4_write_ppf(vc4_state, - vc4_state->src_w[channel], vc4_state->crtc_w); -+ vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel, -+ state->chroma_siting_h); ++ vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, ++ channel, state->chroma_siting_h, ++ state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); } /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { vc4_write_ppf(vc4_state, - vc4_state->src_h[channel], vc4_state->crtc_h); -+ vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel, -+ state->chroma_siting_v); ++ vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, ++ channel, state->chroma_siting_v, ++ state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); vc4_dlist_write(vc4_state, 0xc0c0c0c0); } -@@ -660,7 +865,8 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) +@@ -660,7 +911,8 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) for (i = 0; i < fb->format->num_planes; i++) { /* Even if the bandwidth/plane required for a single frame is * @@ -95918,7 +99220,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 * * when downscaling, we have to read more pixels per line in * the time frame reserved for a single line, so the bandwidth -@@ -669,11 +875,11 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) +@@ -669,11 +921,11 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) * load by this number. We're likely over-estimating the read * demand, but that's better than under-estimating it. */ @@ -95934,25 +99236,26 @@ index 5948e34f7f81..2d1039aa2dcf 100644 vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w; } -@@ -684,39 +890,88 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) +@@ -684,43 +936,208 @@ static void vc4_plane_calc_load(struct drm_plane_state *state) static int vc4_plane_allocate_lbm(struct drm_plane_state *state) { - struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + struct drm_device *drm = state->plane->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = vc4->hvs; + struct drm_plane *plane = state->plane; struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); -- unsigned long irqflags; ++ struct vc4_lbm_refcounts *refcount; + unsigned long irqflags; ++ int lbm_handle; u32 lbm_size; ++ int ret; lbm_size = vc4_lbm_size(state); -- if (!lbm_size) -+ if (!lbm_size) { -+ vc4_state->lbm_size = 0; + if (!lbm_size) return 0; -+ } -+ + + /* + * NOTE: BCM2712 doesn't need to be aligned, since the size + * returned by vc4_lbm_size() is in words already. @@ -95964,28 +99267,91 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + + drm_dbg_driver(drm, "[PLANE:%d:%s] LBM Allocation Size: %u\n", + plane->base.id, plane->name, lbm_size); - ++ if (WARN_ON(!vc4_state->lbm_offset)) return -EINVAL; -- /* Allocate the LBM memory that the HVS will use for temporary -- * storage due to our scaling/format conversion. -+ /* FIXME: Add loop here that ensures that the total LBM assigned in this -+ * state is less than the total lbm size + /* Allocate the LBM memory that the HVS will use for temporary + * storage due to our scaling/format conversion. */ - if (!drm_mm_node_allocated(&vc4_state->lbm)) { - int ret; -- ++ lbm_handle = vc4_state->lbm_handle; ++ if (lbm_handle && ++ hvs->lbm_refcounts[lbm_handle].size == lbm_size) { ++ /* Allocation is the same size as the previous user of ++ * the plane. Keep the allocation. ++ */ ++ vc4_state->lbm_handle = lbm_handle; ++ } else { ++ if (lbm_handle && ++ refcount_dec_and_test(&hvs->lbm_refcounts[lbm_handle].refcount)) { ++ vc4_plane_release_lbm_ida(hvs, lbm_handle); ++ vc4_state->lbm_handle = 0; ++ } ++ ++ lbm_handle = ida_alloc_range(&hvs->lbm_handles, 1, ++ VC4_NUM_LBM_HANDLES, ++ GFP_KERNEL); ++ if (lbm_handle < 0) { ++ drm_dbg_driver(drm, "Out of lbm_handles\n"); ++ return lbm_handle; ++ } ++ vc4_state->lbm_handle = lbm_handle; ++ ++ refcount = &hvs->lbm_refcounts[lbm_handle]; ++ refcount_set(&refcount->refcount, 1); ++ refcount->size = lbm_size; + - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); -- ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, - &vc4_state->lbm, - lbm_size, - vc4->is_vc5 ? 64 : 32, -+ vc4_state->lbm_size = lbm_size; ++ &refcount->lbm, ++ lbm_size, 1, + 0, 0); +- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); +- +- if (ret) ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ ++ if (ret) { ++ drm_dbg_driver(drm, "Failed to allocate LBM entry: %d\n", ++ ret); ++ refcount_set(&refcount->refcount, 0); ++ ida_free(&hvs->lbm_handles, lbm_handle); ++ vc4_state->lbm_handle = 0; + return ret; +- } else { +- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); ++ } + } + +- vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; ++ vc4_state->dlist[vc4_state->lbm_offset] = hvs->lbm_refcounts[lbm_handle].lbm.start; + + return 0; +} + ++static void vc4_plane_free_lbm(struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int lbm_handle; ++ ++ lbm_handle = vc4_state->lbm_handle; ++ if (!lbm_handle) ++ return; ++ ++ if (refcount_dec_and_test(&hvs->lbm_refcounts[lbm_handle].refcount)) ++ vc4_plane_release_lbm_ida(hvs, lbm_handle); ++ vc4_state->lbm_handle = 0; ++} ++ +static int vc6_plane_allocate_upm(struct drm_plane_state *state) +{ + const struct drm_format_info *info = state->fb->format; @@ -96001,38 +99367,61 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES; + + for (i = 0; i < info->num_planes; i++) { ++ struct vc4_upm_refcounts *refcount; ++ int upm_handle; + unsigned long irqflags; + size_t upm_size; + + upm_size = vc6_upm_size(state, i); + if (!upm_size) + return -EINVAL; ++ upm_handle = vc4_state->upm_handle[i]; + -+ spin_lock_irqsave(&hvs->mm_lock, irqflags); -+ ret = drm_mm_insert_node_generic(&hvs->upm_mm, -+ &vc4_state->upm[i], -+ upm_size, HVS_UBM_WORD_SIZE, - 0, 0); -- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); -+ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); -+ if (ret) { -+ drm_err(drm, "Failed to allocate UPM entry: %d\n", ret); -+ return ret; ++ if (upm_handle && ++ hvs->upm_refcounts[upm_handle].size == upm_size) { ++ /* Allocation is the same size as the previous user of ++ * the plane. Keep the allocation. ++ */ ++ vc4_state->upm_handle[i] = upm_handle; ++ } else { ++ if (upm_handle && ++ refcount_dec_and_test(&hvs->upm_refcounts[upm_handle].refcount)) { ++ vc4_plane_release_upm_ida(hvs, upm_handle); ++ vc4_state->upm_handle[i] = 0; ++ } ++ ++ upm_handle = ida_alloc_range(&hvs->upm_handles, 1, ++ VC4_NUM_UPM_HANDLES, ++ GFP_KERNEL); ++ if (upm_handle < 0) { ++ drm_dbg_driver(drm, "Out of upm_handles\n"); ++ return upm_handle; ++ } ++ vc4_state->upm_handle[i] = upm_handle; ++ ++ refcount = &hvs->upm_refcounts[upm_handle]; ++ refcount_set(&refcount->refcount, 1); ++ refcount->size = upm_size; ++ ++ spin_lock_irqsave(&hvs->mm_lock, irqflags); ++ ret = drm_mm_insert_node_generic(&hvs->upm_mm, ++ &refcount->upm, ++ upm_size, HVS_UBM_WORD_SIZE, ++ 0, 0); ++ spin_unlock_irqrestore(&hvs->mm_lock, irqflags); ++ if (ret) { ++ drm_dbg_driver(drm, "Failed to allocate UPM entry: %d\n", ++ ret); ++ refcount_set(&refcount->refcount, 0); ++ ida_free(&hvs->upm_handles, upm_handle); ++ vc4_state->upm_handle[i] = 0; ++ return ret; ++ } + } - -- if (ret) -+ ret = ida_alloc_range(&hvs->upm_handles, 1, 32, GFP_KERNEL); -+ if (ret < 0) - return ret; -- } else { -- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); -- } - -- vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; -+ vc4_state->upm_handle[i] = ret; + ++ refcount = &hvs->upm_refcounts[upm_handle]; + vc4_state->dlist[vc4_state->ptr0_offset[i]] |= -+ VC4_SET_FIELD(vc4_state->upm[i].start / HVS_UBM_WORD_SIZE, ++ VC4_SET_FIELD(refcount->upm.start / HVS_UBM_WORD_SIZE, + SCALER6_PTR0_UPM_BASE) | + VC4_SET_FIELD(vc4_state->upm_handle[i] - 1, + SCALER6_PTR0_UPM_HANDLE) | @@ -96042,7 +99431,34 @@ index 5948e34f7f81..2d1039aa2dcf 100644 return 0; } -@@ -768,6 +1023,11 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { + ++static void vc6_plane_free_upm(struct drm_plane_state *state) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); ++ struct drm_device *drm = state->plane->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_hvs *hvs = vc4->hvs; ++ unsigned int i; ++ ++ WARN_ON_ONCE(vc4->gen < VC4_GEN_6); ++ ++ for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) { ++ unsigned int upm_handle; ++ ++ upm_handle = vc4_state->upm_handle[i]; ++ if (!upm_handle) ++ continue; ++ ++ if (refcount_dec_and_test(&hvs->upm_refcounts[upm_handle].refcount)) ++ vc4_plane_release_upm_ida(hvs, upm_handle); ++ vc4_state->upm_handle[i] = 0; ++ } ++} ++ + /* + * The colorspace conversion matrices are held in 3 entries in the dlist. + * Create an array of them, with entries for each full and limited mode, and +@@ -768,6 +1185,11 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) { @@ -96054,7 +99470,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 if (!state->fb->format->has_alpha) return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, SCALER_POS2_ALPHA_MODE); -@@ -789,6 +1049,17 @@ static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) +@@ -789,6 +1211,17 @@ static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) { @@ -96072,7 +99488,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 if (!state->fb->format->has_alpha) return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, SCALER5_CTL2_ALPHA_MODE); -@@ -808,6 +1079,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) +@@ -808,6 +1241,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) } } @@ -96094,7 +99510,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Writes out a full display list for an active plane to the plane's * private dlist state. */ -@@ -826,9 +1112,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -826,9 +1274,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, bool mix_plane_alpha; bool covers_screen; u32 scl0, scl1, pitch0; @@ -96107,7 +99523,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 int ret, i; if (vc4_state->dlist_initialized) -@@ -838,6 +1126,15 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -838,6 +1288,15 @@ static int vc4_plane_mode_set(struct drm_plane *plane, if (ret) return ret; @@ -96123,7 +99539,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB * and 4:4:4, scl1 should be set to scl0 so both channels of * the scaler do the same thing. For YUV, the Y plane needs -@@ -858,9 +1155,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -858,9 +1317,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, DRM_MODE_REFLECT_Y); /* We must point to the last line when Y reflection is enabled. */ @@ -96137,7 +99553,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 switch (base_format_mod) { case DRM_FORMAT_MOD_LINEAR: -@@ -871,13 +1170,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -871,13 +1332,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * out. */ for (i = 0; i < num_planes; i++) { @@ -96153,7 +99569,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 } break; -@@ -898,7 +1192,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -898,7 +1354,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * pitch * tile_h == tile_size * tiles_per_row */ u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); @@ -96162,7 +99578,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 u32 tiles_r = tiles_w - tiles_l; u32 tiles_t = src_y >> tile_h_shift; /* Intra-tile offsets, which modify the base address (the -@@ -908,7 +1202,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -908,7 +1364,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 tile_y = (src_y >> 4) & 1; u32 subtile_y = (src_y >> 2) & 3; u32 utile_y = src_y & 3; @@ -96171,7 +99587,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 u32 y_off = src_y & tile_h_mask; /* When Y reflection is requested we must set the -@@ -932,19 +1226,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -932,19 +1388,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); @@ -96198,7 +99614,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 } break; -@@ -1004,7 +1297,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1004,7 +1459,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * of the 12-pixels in that 128-bit word is the * first pixel to be used */ @@ -96207,7 +99623,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 u32 aligned = remaining_pixels / 12; u32 last_bits = remaining_pixels % 12; -@@ -1026,18 +1319,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1026,18 +1481,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, return -EINVAL; } pix_per_tile = tile_w / fb->format->cpp[0]; @@ -96231,7 +99647,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 } pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); -@@ -1050,6 +1341,28 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1050,6 +1503,28 @@ static int vc4_plane_mode_set(struct drm_plane *plane, return -EINVAL; } @@ -96260,7 +99676,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Don't waste cycles mixing with plane alpha if the set alpha * is opaque or there is no per-pixel alpha information. * In any case we use the alpha property value as the fixed alpha. -@@ -1057,7 +1370,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1057,7 +1532,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && fb->format->has_alpha; @@ -96269,7 +99685,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Control word */ vc4_dlist_write(vc4_state, SCALER_CTL0_VALID | -@@ -1092,10 +1405,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1092,10 +1567,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | vc4_hvs4_get_alpha_blend_mode(state) | @@ -96282,7 +99698,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Position Word 3: Context. Written by the HVS. */ vc4_dlist_write(vc4_state, 0xc0c0c0c0); -@@ -1148,10 +1459,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1148,10 +1621,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, /* Position Word 2: Source Image Size */ vc4_state->pos2_offset = vc4_state->dlist_count; vc4_dlist_write(vc4_state, @@ -96295,7 +99711,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Position Word 3: Context. Written by the HVS. */ vc4_dlist_write(vc4_state, 0xc0c0c0c0); -@@ -1162,9 +1471,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1162,9 +1633,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * * The pointers may be any byte address. */ @@ -96312,20 +99728,60 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Pointer Context Word 0/1/2: Written by the HVS */ for (i = 0; i < num_planes; i++) -@@ -1274,6 +1587,426 @@ static int vc4_plane_mode_set(struct drm_plane *plane, +@@ -1234,7 +1709,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, + vc4_state->y_scaling[0] == VC4_SCALING_PPF || + vc4_state->x_scaling[1] == VC4_SCALING_PPF || + vc4_state->y_scaling[1] == VC4_SCALING_PPF) { +- u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, ++ struct drm_mm_node *filter; ++ ++ switch (state->scaling_filter) { ++ case DRM_SCALING_FILTER_DEFAULT: ++ default: ++ filter = &vc4->hvs->mitchell_netravali_filter; ++ break; ++ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: ++ filter = &vc4->hvs->nearest_neighbour_filter; ++ break; ++ } ++ u32 kernel = VC4_SET_FIELD(filter->start, + SCALER_PPF_KERNEL_OFFSET); + + /* HPPF plane 0 */ +@@ -1274,49 +1760,506 @@ static int vc4_plane_mode_set(struct drm_plane *plane, return 0; } +-/* If a modeset involves changing the setup of a plane, the atomic +- * infrastructure will call this to validate a proposed plane setup. +- * However, if a plane isn't getting updated, this (and the +- * corresponding vc4_plane_atomic_update) won't get called. Thus, we +- * compute the dlist here and have all active plane dlists get updated +- * in the CRTC's flush. +- */ +-static int vc4_plane_atomic_check(struct drm_plane *plane, +- struct drm_atomic_state *state) +static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state) -+{ + { +- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, +- plane); +- struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state); +- int ret; +- +- vc4_state->dlist_count = 0; + struct drm_plane_state *state = &vc4_state->base; + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + u32 ret = 0; -+ + +- if (!plane_enabled(new_plane_state)) +- return 0; + if (vc4_state->is_yuv) { + enum drm_color_encoding color_encoding = state->color_encoding; + enum drm_color_range color_range = state->color_range; -+ + +- ret = vc4_plane_mode_set(plane, new_plane_state); +- if (ret) +- return ret; + /* CSC pre-loaded with: + * 0 = BT601 limited range + * 1 = BT709 limited range @@ -96338,7 +99794,9 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + color_encoding = DRM_COLOR_YCBCR_BT601; + if (color_range > DRM_COLOR_YCBCR_FULL_RANGE) + color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; -+ + +- return vc4_plane_allocate_lbm(new_plane_state); +-} + if (vc4->step_d0) { + ret |= SCALER6D0_CTL2_CSC_ENABLE; + ret |= VC4_SET_FIELD(color_encoding + (color_range * 3), @@ -96349,13 +99807,26 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + SCALER6_CTL2_BRCM_CFC_CONTROL); + } + } -+ + +-static void vc4_plane_atomic_update(struct drm_plane *plane, +- struct drm_atomic_state *state) +-{ +- /* No contents here. Since we don't know where in the CRTC's +- * dlist we should be stored, our dlist is uploaded to the +- * hardware with vc4_plane_write_dlist() at CRTC atomic_flush +- * time. +- */ + return ret; -+} -+ + } + +-u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) +static int vc6_plane_mode_set(struct drm_plane *plane, + struct drm_plane_state *state) -+{ + { +- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); +- int i; +- int idx; +- + struct drm_device *drm = plane->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); @@ -96687,9 +100158,19 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + vc4_state->y_scaling[0] == VC4_SCALING_PPF || + vc4_state->x_scaling[1] == VC4_SCALING_PPF || + vc4_state->y_scaling[1] == VC4_SCALING_PPF) { -+ u32 kernel = -+ VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, -+ SCALER_PPF_KERNEL_OFFSET); ++ struct drm_mm_node *filter; ++ ++ switch (state->scaling_filter) { ++ case DRM_SCALING_FILTER_DEFAULT: ++ default: ++ filter = &vc4->hvs->mitchell_netravali_filter; ++ break; ++ case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: ++ filter = &vc4->hvs->nearest_neighbour_filter; ++ break; ++ } ++ u32 kernel = VC4_SET_FIELD(filter->start, ++ SCALER_PPF_KERNEL_OFFSET); + + /* HPPF plane 0 */ + vc4_dlist_write(vc4_state, kernel); @@ -96736,27 +100217,36 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + return 0; +} + - /* If a modeset involves changing the setup of a plane, the atomic - * infrastructure will call this to validate a proposed plane setup. - * However, if a plane isn't getting updated, this (and the -@@ -1281,9 +2014,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane, - * compute the dlist here and have all active plane dlists get updated - * in the CRTC's flush. - */ --static int vc4_plane_atomic_check(struct drm_plane *plane, -- struct drm_atomic_state *state) ++/* If a modeset involves changing the setup of a plane, the atomic ++ * infrastructure will call this to validate a proposed plane setup. ++ * However, if a plane isn't getting updated, this (and the ++ * corresponding vc4_plane_atomic_update) won't get called. Thus, we ++ * compute the dlist here and have all active plane dlists get updated ++ * in the CRTC's flush. ++ */ +int vc4_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) - { ++{ + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state); -@@ -1294,11 +2028,28 @@ static int vc4_plane_atomic_check(struct drm_plane *plane, - if (!plane_enabled(new_plane_state)) - return 0; - -- ret = vc4_plane_mode_set(plane, new_plane_state); ++ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, ++ plane); ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state); ++ int ret; ++ ++ vc4_state->dlist_count = 0; ++ ++ if (!plane_enabled(new_plane_state)) { ++ struct drm_plane_state *old_plane_state = ++ drm_atomic_get_old_plane_state(state, plane); ++ ++ if (old_plane_state && plane_enabled(old_plane_state)) { ++ if (vc4->gen >= VC4_GEN_6) ++ vc6_plane_free_upm(new_plane_state); ++ vc4_plane_free_lbm(new_plane_state); ++ } ++ return 0; ++ } ++ + if (vc4->gen >= VC4_GEN_6) + ret = vc6_plane_mode_set(plane, new_plane_state); + else @@ -96769,10 +100259,9 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + return 0; + + ret = vc4_plane_allocate_lbm(new_plane_state); - if (ret) - return ret; - -- return vc4_plane_allocate_lbm(new_plane_state); ++ if (ret) ++ return ret; ++ + if (vc4->gen >= VC4_GEN_6) { + ret = vc6_plane_allocate_upm(new_plane_state); + if (ret) @@ -96780,10 +100269,28 @@ index 5948e34f7f81..2d1039aa2dcf 100644 + } + + return 0; - } ++} ++ ++static void vc4_plane_atomic_update(struct drm_plane *plane, ++ struct drm_atomic_state *state) ++{ ++ /* No contents here. Since we don't know where in the CRTC's ++ * dlist we should be stored, our dlist is uploaded to the ++ * hardware with vc4_plane_write_dlist() at CRTC atomic_flush ++ * time. ++ */ ++} ++ ++u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) ++{ ++ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); ++ int i; ++ int idx; ++ + if (!drm_dev_enter(plane->dev, &idx)) + goto out; - static void vc4_plane_atomic_update(struct drm_plane *plane, -@@ -1346,7 +2097,8 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) +@@ -1346,7 +2289,8 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); @@ -96793,7 +100300,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 int idx; if (!drm_dev_enter(plane->dev, &idx)) -@@ -1356,19 +2108,38 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) +@@ -1356,19 +2300,38 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) * because this is only called on the primary plane. */ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); @@ -96843,7 +100350,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 drm_dev_exit(idx); } -@@ -1423,8 +2194,6 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, +@@ -1423,8 +2386,6 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, sizeof(vc4_state->y_scaling)); vc4_state->is_unity = new_vc4_state->is_unity; vc4_state->is_yuv = new_vc4_state->is_yuv; @@ -96852,7 +100359,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ -@@ -1432,8 +2201,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, +@@ -1432,8 +2393,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, new_vc4_state->dlist[vc4_state->pos0_offset]; vc4_state->dlist[vc4_state->pos2_offset] = new_vc4_state->dlist[vc4_state->pos2_offset]; @@ -96863,7 +100370,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 /* Note that we can't just call vc4_plane_write_dlist() * because that would smash the context data that the HVS is -@@ -1443,8 +2212,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, +@@ -1443,8 +2404,8 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, &vc4_state->hw_dlist[vc4_state->pos0_offset]); writel(vc4_state->dlist[vc4_state->pos2_offset], &vc4_state->hw_dlist[vc4_state->pos2_offset]); @@ -96874,7 +100381,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 drm_dev_exit(idx); } -@@ -1454,11 +2223,15 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, +@@ -1454,11 +2415,15 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); @@ -96891,7 +100398,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 if (ret) return ret; -@@ -1471,7 +2244,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, +@@ -1471,7 +2436,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || @@ -96900,7 +100407,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state)) return -EINVAL; -@@ -1481,7 +2254,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, +@@ -1481,7 +2446,7 @@ static int vc4_plane_atomic_async_check(struct drm_plane *plane, for (i = 0; i < new_vc4_state->dlist_count; i++) { if (i == new_vc4_state->pos0_offset || i == new_vc4_state->pos2_offset || @@ -96909,7 +100416,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 (new_vc4_state->lbm_offset && i == new_vc4_state->lbm_offset)) continue; -@@ -1629,7 +2402,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, +@@ -1629,7 +2594,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, }; for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { @@ -96918,7 +100425,7 @@ index 5948e34f7f81..2d1039aa2dcf 100644 formats[num_formats] = hvs_formats[i].drm; num_formats++; } -@@ -1644,7 +2417,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, +@@ -1644,7 +2609,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, return ERR_CAST(vc4_plane); plane = &vc4_plane->base; @@ -96927,10 +100434,14 @@ index 5948e34f7f81..2d1039aa2dcf 100644 drm_plane_helper_add(plane, &vc5_plane_helper_funcs); else drm_plane_helper_add(plane, &vc4_plane_helper_funcs); -@@ -1669,6 +2442,8 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, +@@ -1669,6 +2634,12 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); ++ drm_plane_create_scaling_filter_property(plane, ++ BIT(DRM_SCALING_FILTER_DEFAULT) | ++ BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); ++ + drm_plane_create_chroma_siting_properties(plane, 0, 0); + if (type == DRM_PLANE_TYPE_PRIMARY) @@ -97566,7 +101077,7 @@ index ffe1f7d1b911..b87d5f8ad4b8 100644 }; diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c -index 04ac7805e6d5..14d268f80fa5 100644 +index 04ac7805e6d5..2fdeb76f05c0 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c @@ -127,7 +127,7 @@ static int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused) @@ -97614,6 +101125,15 @@ index 04ac7805e6d5..14d268f80fa5 100644 return; mutex_lock(&vc4->bin_bo_lock); +@@ -376,6 +376,8 @@ static int vc4_v3d_runtime_suspend(struct device *dev) + + vc4_irq_disable(&vc4->base); + ++ /* we no longer require a minimum clock rate */ ++ clk_set_min_rate(v3d->clk, 0); + clk_disable_unprepare(v3d->clk); + + return 0; diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 7dff3ca5af6b..722c0f8909d2 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c @@ -98142,10 +101662,10 @@ index 000000000000..e8d2b4b162f7 + VC_IMAGE_YUVINFO_CSC_REC_2020 = 9, +}; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 0a4daff4846f..a2b2fb75b5ed 100644 +index dd696cb559ae..eec8a133ff73 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h -@@ -239,6 +239,9 @@ +@@ -242,6 +242,9 @@ #define USB_VENDOR_ID_BAANTO 0x2453 #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 @@ -98155,7 +101675,7 @@ index 0a4daff4846f..a2b2fb75b5ed 100644 #define USB_VENDOR_ID_BELKIN 0x050d #define USB_DEVICE_ID_FLIP_KVM 0x3201 -@@ -1404,6 +1407,9 @@ +@@ -1420,6 +1423,9 @@ #define USB_VENDOR_ID_XIAOMI 0x2717 #define USB_DEVICE_ID_MI_SILENT_MOUSE 0x5014 @@ -98218,10 +101738,10 @@ index 257dd73e37bf..fb588ac24acc 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index b7ce1654c48e..5b3cc16b9512 100644 +index ee2eaf825c62..ad9b4810b496 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -2386,6 +2386,13 @@ config SENSORS_INTEL_M10_BMC_HWMON +@@ -2390,6 +2390,13 @@ config SENSORS_INTEL_M10_BMC_HWMON sensors monitor various telemetry data of different components on the card, e.g. board temperature, FPGA core temperature/voltage/current. @@ -98247,6 +101767,29 @@ index cd8bfab85056..04bd32e1f93b 100644 obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o +diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c +index 952506779336..aee9adfa06aa 100644 +--- a/drivers/hwmon/adt7410.c ++++ b/drivers/hwmon/adt7410.c +@@ -94,10 +94,18 @@ static const struct i2c_device_id adt7410_ids[] = { + }; + MODULE_DEVICE_TABLE(i2c, adt7410_ids); + ++static const struct of_device_id adt7410_of_ids[] = { ++ { .compatible = "adi,adt7410" }, ++ { .compatible = "adi,adt7420" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, adt7410_of_ids); ++ + static struct i2c_driver adt7410_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "adt7410", ++ .of_match_table = adt7410_of_ids, + .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), + }, + .probe = adt7410_i2c_probe, diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index f136bf3ff40a..558ef3af4486 100644 --- a/drivers/hwmon/aht10.c @@ -98480,7 +102023,7 @@ index 29f0e4945f19..00e92ff352b0 100644 .probe = emc2305_probe, .remove = emc2305_remove, diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c -index 6e4516c2ab89..131895d5a031 100644 +index b67bc9e833c0..131895d5a031 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -12,6 +12,7 @@ @@ -98512,42 +102055,6 @@ index 6e4516c2ab89..131895d5a031 100644 /* This handler assumes self resetting edge triggered interrupt. */ static irqreturn_t pulse_handler(int irq, void *dev_id) { -@@ -151,7 +159,7 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) - } - - state->enabled = true; -- ret = pwm_apply_state(ctx->pwm, state); -+ ret = pwm_apply_might_sleep(ctx->pwm, state); - if (ret) { - dev_err(ctx->dev, "failed to enable PWM\n"); - goto disable_regulator; -@@ -181,7 +189,7 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) - - state->enabled = false; - state->duty_cycle = 0; -- ret = pwm_apply_state(ctx->pwm, state); -+ ret = pwm_apply_might_sleep(ctx->pwm, state); - if (ret) { - dev_err(ctx->dev, "failed to disable PWM\n"); - return ret; -@@ -207,7 +215,7 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) - - period = state->period; - state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); -- ret = pwm_apply_state(ctx->pwm, state); -+ ret = pwm_apply_might_sleep(ctx->pwm, state); - if (ret) - return ret; - ret = pwm_fan_power_on(ctx); -@@ -278,7 +286,7 @@ static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) - state, - &enable_regulator); - -- pwm_apply_state(ctx->pwm, state); -+ pwm_apply_might_sleep(ctx->pwm, state); - pwm_fan_switch_power(ctx, enable_regulator); - pwm_fan_update_state(ctx, 0); - } @@ -335,7 +343,10 @@ static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, } return -EOPNOTSUPP; @@ -99792,7 +103299,7 @@ index b92de1944221..71a74de9fa5a 100644 static const struct i2c_algorithm bcm2835_i2c_algo = { diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c -index 83803a63e23f..5cb4fcf562eb 100644 +index c283743916fe..a53514813924 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -57,6 +57,8 @@ static char *abort_sources[] = { @@ -99845,7 +103352,7 @@ index 83803a63e23f..5cb4fcf562eb 100644 } EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed); -@@ -574,8 +603,16 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) +@@ -590,8 +619,16 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) { unsigned long abort_source = dev->abort_source; @@ -99862,7 +103369,7 @@ index 83803a63e23f..5cb4fcf562eb 100644 if (abort_source & DW_IC_TX_ABRT_NOACK) { for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) dev_dbg(dev->dev, -@@ -590,6 +627,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) +@@ -606,6 +643,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) return -EAGAIN; else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) return -EINVAL; /* wrong msgs[] data */ @@ -99872,7 +103379,7 @@ index 83803a63e23f..5cb4fcf562eb 100644 return -EIO; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h -index 03483288ecf8..20c29e6c997f 100644 +index d4909e9b1c84..15c8520bde40 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -79,9 +79,12 @@ @@ -99888,19 +103395,18 @@ index 03483288ecf8..20c29e6c997f 100644 #define DW_IC_COMP_TYPE 0xfc #define DW_IC_COMP_TYPE_VALUE 0x44570140 /* "DW" + 0x0140 */ -@@ -109,20 +112,25 @@ - DW_IC_INTR_RX_UNDER | \ - DW_IC_INTR_RD_REQ) +@@ -111,6 +114,7 @@ -+#define DW_IC_ENABLE_ENABLE BIT(0) + #define DW_IC_ENABLE_ENABLE BIT(0) #define DW_IC_ENABLE_ABORT BIT(1) +#define DW_IC_ENABLE_BUS_RECOVERY BIT(3) #define DW_IC_STATUS_ACTIVITY BIT(0) #define DW_IC_STATUS_TFE BIT(2) - #define DW_IC_STATUS_RFNE BIT(3) +@@ -118,13 +122,16 @@ #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) + #define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7) +#define DW_IC_STATUS_SDA_STUCK_NOT_RECOVERED BIT(11) #define DW_IC_SDA_HOLD_RX_SHIFT 16 @@ -99914,7 +103420,7 @@ index 03483288ecf8..20c29e6c997f 100644 #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2) -@@ -161,6 +169,7 @@ +@@ -163,6 +170,7 @@ #define ABRT_SLAVE_FLUSH_TXFIFO 13 #define ABRT_SLAVE_ARBLOST 14 #define ABRT_SLAVE_RD_INTX 15 @@ -99922,7 +103428,7 @@ index 03483288ecf8..20c29e6c997f 100644 #define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK) #define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK) -@@ -176,6 +185,7 @@ +@@ -178,6 +186,7 @@ #define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX) #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) @@ -99930,7 +103436,7 @@ index 03483288ecf8..20c29e6c997f 100644 #define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ DW_IC_TX_ABRT_10ADDR1_NOACK | \ -@@ -289,6 +299,7 @@ struct dw_i2c_dev { +@@ -291,6 +300,7 @@ struct dw_i2c_dev { u16 fp_lcnt; u16 hs_hcnt; u16 hs_lcnt; @@ -99939,7 +103445,7 @@ index 03483288ecf8..20c29e6c997f 100644 void (*release_lock)(void); int semaphore_idx; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c -index 85dbd0eb5392..7593bcf03b9f 100644 +index 579c668cb78a..f32ed9486ac0 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -38,6 +38,34 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev) @@ -100065,7 +103571,7 @@ index 85dbd0eb5392..7593bcf03b9f 100644 regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER, ic_con); -@@ -472,6 +528,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) +@@ -500,6 +556,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) regmap_read(dev->map, DW_IC_RXFLR, &flr); rx_limit = dev->rx_fifo_depth - flr; @@ -100080,7 +103586,7 @@ index 85dbd0eb5392..7593bcf03b9f 100644 while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { u32 cmd = 0; -@@ -743,7 +807,7 @@ static const struct i2c_algorithm i2c_dw_algo = { +@@ -781,7 +845,7 @@ static const struct i2c_algorithm i2c_dw_algo = { }; static const struct i2c_adapter_quirks i2c_dw_quirks = { @@ -100089,7 +103595,7 @@ index 85dbd0eb5392..7593bcf03b9f 100644 }; static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) -@@ -876,7 +940,8 @@ void i2c_dw_configure_master(struct dw_i2c_dev *dev) +@@ -914,7 +978,8 @@ void i2c_dw_configure_master(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; @@ -100099,7 +103605,7 @@ index 85dbd0eb5392..7593bcf03b9f 100644 dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN; -@@ -983,6 +1048,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) +@@ -1021,6 +1086,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) struct i2c_adapter *adap = &dev->adapter; unsigned long irq_flags; unsigned int ic_con; @@ -100107,7 +103613,7 @@ index 85dbd0eb5392..7593bcf03b9f 100644 int ret; init_completion(&dev->cmd_complete); -@@ -1018,7 +1084,11 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) +@@ -1056,7 +1122,11 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) if (ret) return ret; @@ -100215,306 +103721,159 @@ index d99bf3ae0fe8..b90cf0492bc4 100644 }, .probe = veml6070_probe, .remove = veml6070_remove, -diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig -index ac6925ce8366..6e12fd8e4376 100644 ---- a/drivers/input/joystick/Kconfig -+++ b/drivers/input/joystick/Kconfig -@@ -412,4 +412,12 @@ config JOYSTICK_SENSEHAT - To compile this driver as a module, choose M here: the - module will be called sensehat_joystick. +diff --git a/drivers/input/joystick/sensehat-joystick.c b/drivers/input/joystick/sensehat-joystick.c +index a84df39d3b2f..f24beb98e444 100644 +--- a/drivers/input/joystick/sensehat-joystick.c ++++ b/drivers/input/joystick/sensehat-joystick.c +@@ -28,7 +28,7 @@ struct sensehat_joystick { + }; -+config JOYSTICK_RPISENSE -+ tristate "Raspberry Pi Sense HAT joystick" -+ depends on GPIOLIB && INPUT -+ select MFD_RPISENSE_CORE + static const unsigned int keymap[] = { +- BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT, ++ KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT + }; + + static irqreturn_t sensehat_joystick_report(int irq, void *cookie) +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +index a1b037891af2..a1cf56096156 100644 +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -27,6 +27,7 @@ struct matrix_keypad { + const struct matrix_keypad_platform_data *pdata; + struct input_dev *input_dev; + unsigned int row_shift; ++ unsigned int row_irqs[MATRIX_MAX_ROWS]; + + DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); + +@@ -92,7 +93,7 @@ static void enable_row_irqs(struct matrix_keypad *keypad) + enable_irq(pdata->clustered_irq); + else { + for (i = 0; i < pdata->num_row_gpios; i++) +- enable_irq(gpio_to_irq(pdata->row_gpios[i])); ++ enable_irq(keypad->row_irqs[i]); + } + } + +@@ -105,7 +106,7 @@ static void disable_row_irqs(struct matrix_keypad *keypad) + disable_irq_nosync(pdata->clustered_irq); + else { + for (i = 0; i < pdata->num_row_gpios; i++) +- disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); ++ disable_irq_nosync(keypad->row_irqs[i]); + } + } + +@@ -233,7 +234,6 @@ static void matrix_keypad_stop(struct input_dev *dev) + static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- unsigned int gpio; + int i; + + if (pdata->clustered_irq > 0) { +@@ -241,21 +241,16 @@ static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) + keypad->gpio_all_disabled = true; + } else { + +- for (i = 0; i < pdata->num_row_gpios; i++) { +- if (!test_bit(i, keypad->disabled_gpios)) { +- gpio = pdata->row_gpios[i]; +- +- if (enable_irq_wake(gpio_to_irq(gpio)) == 0) ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ if (!test_bit(i, keypad->disabled_gpios)) ++ if (enable_irq_wake(keypad->row_irqs[i]) == 0) + __set_bit(i, keypad->disabled_gpios); +- } +- } + } + } + + static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- unsigned int gpio; + int i; + + if (pdata->clustered_irq > 0) { +@@ -264,12 +259,9 @@ static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) + keypad->gpio_all_disabled = false; + } + } else { +- for (i = 0; i < pdata->num_row_gpios; i++) { +- if (test_and_clear_bit(i, keypad->disabled_gpios)) { +- gpio = pdata->row_gpios[i]; +- disable_irq_wake(gpio_to_irq(gpio)); +- } +- } ++ for (i = 0; i < pdata->num_row_gpios; i++) ++ if (test_and_clear_bit(i, keypad->disabled_gpios)) ++ disable_irq_wake(keypad->row_irqs[i]); + } + } + +@@ -306,7 +298,7 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, + struct matrix_keypad *keypad) + { + const struct matrix_keypad_platform_data *pdata = keypad->pdata; +- int i, err; ++ int i, irq, err; + + /* initialized strobe lines as outputs, activated */ + for (i = 0; i < pdata->num_col_gpios; i++) { +@@ -345,11 +337,19 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, + } + } else { + for (i = 0; i < pdata->num_row_gpios; i++) { +- err = request_any_context_irq( +- gpio_to_irq(pdata->row_gpios[i]), ++ irq = gpio_to_irq(pdata->row_gpios[i]); ++ if (irq < 0) { ++ err = irq; ++ dev_err(&pdev->dev, ++ "Unable to convert GPIO line %i to irq: %d\n", ++ pdata->row_gpios[i], err); ++ goto err_free_irqs; ++ } + -+ help -+ This is the joystick driver for the Raspberry Pi Sense HAT ++ err = request_any_context_irq(irq, + matrix_keypad_interrupt, + IRQF_TRIGGER_RISING | +- IRQF_TRIGGER_FALLING, ++ IRQF_TRIGGER_FALLING, + "matrix-keypad", keypad); + if (err < 0) { + dev_err(&pdev->dev, +@@ -357,6 +357,8 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, + pdata->row_gpios[i]); + goto err_free_irqs; + } + - endif -diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile -index 3937535f0098..038a76a2513a 100644 ---- a/drivers/input/joystick/Makefile -+++ b/drivers/input/joystick/Makefile -@@ -40,3 +40,4 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o - obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o - obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o - obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o -+obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o -diff --git a/drivers/input/joystick/rpisense-js.c b/drivers/input/joystick/rpisense-js.c -new file mode 100644 -index 000000000000..6a416769065d ---- /dev/null -+++ b/drivers/input/joystick/rpisense-js.c -@@ -0,0 +1,153 @@ -+/* -+ * Raspberry Pi Sense HAT joystick driver -+ * http://raspberrypi.org -+ * -+ * Copyright (C) 2015 Raspberry Pi -+ * -+ * Author: Serge Schneider -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include -+ -+#include -+#include -+ -+static struct rpisense *rpisense; -+static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; -+ -+static void keys_work_fn(struct work_struct *work) -+{ -+ int i; -+ static s32 prev_keys; -+ struct rpisense_js *rpisense_js = &rpisense->joystick; -+ s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS); -+ s32 changes = keys ^ prev_keys; -+ -+ prev_keys = keys; -+ for (i = 0; i < 5; i++) { -+ if (changes & 1) { -+ input_report_key(rpisense_js->keys_dev, -+ keymap[i], keys & 1); -+ } -+ changes >>= 1; -+ keys >>= 1; -+ } -+ input_sync(rpisense_js->keys_dev); -+} -+ -+static irqreturn_t keys_irq_handler(int irq, void *pdev) -+{ -+ struct rpisense_js *rpisense_js = &rpisense->joystick; -+ -+ schedule_work(&rpisense_js->keys_work_s); -+ return IRQ_HANDLED; -+} -+ -+static int rpisense_js_probe(struct platform_device *pdev) -+{ -+ int ret; -+ int i; -+ struct rpisense_js *rpisense_js; -+ -+ rpisense = rpisense_get_dev(); -+ rpisense_js = &rpisense->joystick; -+ -+ INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn); -+ -+ rpisense_js->keys_dev = input_allocate_device(); -+ if (!rpisense_js->keys_dev) { -+ dev_err(&pdev->dev, "Could not allocate input device.\n"); -+ return -ENOMEM; -+ } -+ -+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY); -+ for (i = 0; i < ARRAY_SIZE(keymap); i++) { -+ set_bit(keymap[i], -+ rpisense_js->keys_dev->keybit); -+ } -+ -+ rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick"; -+ rpisense_js->keys_dev->phys = "rpi-sense-joy/input0"; -+ rpisense_js->keys_dev->id.bustype = BUS_I2C; -+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); -+ rpisense_js->keys_dev->keycode = keymap; -+ rpisense_js->keys_dev->keycodesize = sizeof(unsigned char); -+ rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap); -+ -+ ret = input_register_device(rpisense_js->keys_dev); -+ if (ret) { -+ dev_err(&pdev->dev, "Could not register input device.\n"); -+ goto err_keys_alloc; -+ } -+ -+ ret = gpiod_direction_input(rpisense_js->keys_desc); -+ if (ret) { -+ dev_err(&pdev->dev, "Could not set keys-int direction.\n"); -+ goto err_keys_reg; -+ } -+ -+ rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc); -+ if (rpisense_js->keys_irq < 0) { -+ dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n"); -+ ret = rpisense_js->keys_irq; -+ goto err_keys_reg; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq, -+ keys_irq_handler, IRQF_TRIGGER_RISING, -+ "keys", &pdev->dev); -+ if (ret) { -+ dev_err(&pdev->dev, "IRQ request failed.\n"); -+ goto err_keys_reg; -+ } -+ return 0; -+err_keys_reg: -+ input_unregister_device(rpisense_js->keys_dev); -+err_keys_alloc: -+ input_free_device(rpisense_js->keys_dev); -+ return ret; -+} -+ -+static int rpisense_js_remove(struct platform_device *pdev) -+{ -+ struct rpisense_js *rpisense_js = &rpisense->joystick; -+ -+ input_unregister_device(rpisense_js->keys_dev); -+ input_free_device(rpisense_js->keys_dev); -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static const struct of_device_id rpisense_js_id[] = { -+ { .compatible = "rpi,rpi-sense-js" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, rpisense_js_id); -+#endif -+ -+static struct platform_device_id rpisense_js_device_id[] = { -+ { .name = "rpi-sense-js" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(platform, rpisense_js_device_id); -+ -+static struct platform_driver rpisense_js_driver = { -+ .probe = rpisense_js_probe, -+ .remove = rpisense_js_remove, -+ .driver = { -+ .name = "rpi-sense-js", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+module_platform_driver(rpisense_js_driver); -+ -+MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver"); -+MODULE_AUTHOR("Serge Schneider "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c -index ce82548916bb..c1fa75c0f970 100644 ---- a/drivers/input/misc/da7280.c -+++ b/drivers/input/misc/da7280.c -@@ -352,7 +352,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled) - state.duty_cycle = period_mag_multi; ++ keypad->row_irqs[i] = irq; + } } -- error = pwm_apply_state(haptics->pwm_dev, &state); -+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); - if (error) - dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error); +@@ -366,7 +368,7 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, -@@ -1175,7 +1175,7 @@ static int da7280_probe(struct i2c_client *client) - /* Sync up PWM state and ensure it is off. */ - pwm_init_state(haptics->pwm_dev, &state); - state.enabled = false; -- error = pwm_apply_state(haptics->pwm_dev, &state); -+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state); - if (error) { - dev_err(dev, "Failed to apply PWM state: %d\n", error); - return error; -diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c -index 1e731d8397c6..5b9aedf4362f 100644 ---- a/drivers/input/misc/pwm-beeper.c -+++ b/drivers/input/misc/pwm-beeper.c -@@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period) - state.period = period; - pwm_set_relative_duty_cycle(&state, 50, 100); + err_free_irqs: + while (--i >= 0) +- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ free_irq(keypad->row_irqs[i], keypad); + i = pdata->num_row_gpios; + err_free_rows: + while (--i >= 0) +@@ -388,7 +390,7 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) + free_irq(pdata->clustered_irq, keypad); + } else { + for (i = 0; i < pdata->num_row_gpios; i++) +- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); ++ free_irq(keypad->row_irqs[i], keypad); + } -- error = pwm_apply_state(beeper->pwm, &state); -+ error = pwm_apply_might_sleep(beeper->pwm, &state); - if (error) - return error; - -@@ -138,7 +138,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) - /* Sync up PWM state and ensure it is off. */ - pwm_init_state(beeper->pwm, &state); - state.enabled = false; -- error = pwm_apply_state(beeper->pwm, &state); -+ error = pwm_apply_might_sleep(beeper->pwm, &state); - if (error) { - dev_err(dev, "failed to apply initial PWM state: %d\n", - error); -diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c -index acac79c488aa..3e5ed685ed8f 100644 ---- a/drivers/input/misc/pwm-vibra.c -+++ b/drivers/input/misc/pwm-vibra.c -@@ -56,7 +56,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) - pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff); - state.enabled = true; - -- err = pwm_apply_state(vibrator->pwm, &state); -+ err = pwm_apply_might_sleep(vibrator->pwm, &state); - if (err) { - dev_err(pdev, "failed to apply pwm state: %d\n", err); - return err; -@@ -67,7 +67,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) - state.duty_cycle = vibrator->direction_duty_cycle; - state.enabled = true; - -- err = pwm_apply_state(vibrator->pwm_dir, &state); -+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); - if (err) { - dev_err(pdev, "failed to apply dir-pwm state: %d\n", err); - pwm_disable(vibrator->pwm); -@@ -160,7 +160,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) - /* Sync up PWM state and ensure it is off. */ - pwm_init_state(vibrator->pwm, &state); - state.enabled = false; -- err = pwm_apply_state(vibrator->pwm, &state); -+ err = pwm_apply_might_sleep(vibrator->pwm, &state); - if (err) { - dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", - err); -@@ -174,7 +174,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) - /* Sync up PWM state and ensure it is off. */ - pwm_init_state(vibrator->pwm_dir, &state); - state.enabled = false; -- err = pwm_apply_state(vibrator->pwm_dir, &state); -+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state); - if (err) { - dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", - err); -diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c -index faea40dd66d0..262d23749440 100644 ---- a/drivers/input/touchscreen/ads7846.c -+++ b/drivers/input/touchscreen/ads7846.c -@@ -1114,6 +1114,16 @@ static const struct of_device_id ads7846_dt_ids[] = { - }; - MODULE_DEVICE_TABLE(of, ads7846_dt_ids); - -+static const struct spi_device_id ads7846_spi_ids[] = { -+ { "tsc2046", 0 }, -+ { "ads7843", 0 }, -+ { "ads7845", 0 }, -+ { "ads7846", 0 }, -+ { "ads7873", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(spi, ads7846_spi_ids); -+ - static const struct ads7846_platform_data *ads7846_get_props(struct device *dev) - { - struct ads7846_platform_data *pdata; -@@ -1390,6 +1400,7 @@ static struct spi_driver ads7846_driver = { - .pm = pm_sleep_ptr(&ads7846_pm), - .of_match_table = ads7846_dt_ids, - }, -+ .id_table = ads7846_spi_ids, - .probe = ads7846_probe, - .remove = ads7846_remove, - }; + for (i = 0; i < pdata->num_row_gpios; i++) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 457d53337fbb..1d2b8df0aea9 100644 +index a365577a1994..b590bc18dde6 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -69,6 +69,7 @@ @@ -100694,7 +104053,7 @@ index 457d53337fbb..1d2b8df0aea9 100644 tsdata->tdata_offset + crclen; } -@@ -1243,7 +1322,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) +@@ -1261,7 +1340,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) if (tsdata->reset_gpio) { usleep_range(5000, 6000); gpiod_set_value_cansleep(tsdata->reset_gpio, 0); @@ -100703,7 +104062,7 @@ index 457d53337fbb..1d2b8df0aea9 100644 } input = devm_input_allocate_device(&client->dev); -@@ -1317,17 +1396,28 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) +@@ -1335,17 +1414,28 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) return error; } @@ -100742,7 +104101,7 @@ index 457d53337fbb..1d2b8df0aea9 100644 } error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); -@@ -1353,6 +1443,10 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) +@@ -1371,6 +1461,10 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) { struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); @@ -100751,8 +104110,8 @@ index 457d53337fbb..1d2b8df0aea9 100644 + cancel_work_sync(&tsdata->work_i2c_poll); + } edt_ft5x06_ts_teardown_debugfs(tsdata); - regmap_exit(tsdata->regmap); } + diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b068ff8afbc9..23134a20ef50 100644 --- a/drivers/input/touchscreen/goodix.c @@ -100911,12 +104270,12 @@ index 87797cc88b32..235dd5f264c5 100644 int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig -index 75131a1b762c..4a95b12a37c4 100644 +index 75131a1b762c..688c17737ef8 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig -@@ -527,4 +527,11 @@ config SMMU_BYPASS_DEV - E.g:SMMU allow iMR3408/3416 Raid bypass at DMA default domain - to support other devices Virtualization through. +@@ -518,6 +518,13 @@ config SPRD_IOMMU + + Say Y here if you want to use the multimedia devices listed above. +config BCM2712_IOMMU + bool "BCM2712 IOMMU driver" @@ -100925,7 +104284,9 @@ index 75131a1b762c..4a95b12a37c4 100644 + help + IOMMU driver for BCM2712 + - endif # IOMMU_SUPPORT + config SMMU_BYPASS_DEV + bool "SMMU bypass streams for some specific devices" + depends on ARM_SMMU_V3=y diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index c2ea11d810ca..036793279696 100644 --- a/drivers/iommu/Makefile @@ -101741,10 +105102,76 @@ index 000000000000..31b811e426dd + +#endif diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c -index 58e7d03fc27c..f98a8f13ecbe 100644 +index 28f63ad432de..3d3cd850c9aa 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c -@@ -2476,11 +2476,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, +@@ -2410,6 +2410,30 @@ size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova, + } + EXPORT_SYMBOL_GPL(iommu_pgsize); + ++static int __iommu_map_pages(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot, ++ gfp_t gfp, size_t *mapped) ++{ ++ const struct iommu_domain_ops *ops = domain->ops; ++ size_t pgsize, count; ++ int ret; ++ ++ pgsize = iommu_pgsize(domain, iova, paddr, size, &count); ++ ++ pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %zu\n", ++ iova, &paddr, pgsize, count); ++ ++ if (ops->map_pages) { ++ ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot, ++ gfp, mapped); ++ } else { ++ ret = ops->map(domain, iova, paddr, pgsize, prot, gfp); ++ *mapped = ret ? 0 : pgsize; ++ } ++ ++ return ret; ++} ++ + static int __iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { +@@ -2420,12 +2444,13 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t orig_paddr = paddr; + int ret = 0; + ++ if (unlikely(!(ops->map || ops->map_pages) || ++ domain->pgsize_bitmap == 0UL)) ++ return -ENODEV; ++ + if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) + return -EINVAL; + +- if (WARN_ON(!ops->map_pages || domain->pgsize_bitmap == 0UL)) +- return -ENODEV; +- + /* find out the minimum page size supported */ + min_pagesz = 1 << __ffs(domain->pgsize_bitmap); + +@@ -2443,14 +2468,10 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, + pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); + + while (size) { +- size_t pgsize, count, mapped = 0; +- +- pgsize = iommu_pgsize(domain, iova, paddr, size, &count); ++ size_t mapped = 0; + +- pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %zu\n", +- iova, &paddr, pgsize, count); +- ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot, +- gfp, &mapped); ++ ret = __iommu_map_pages(domain, iova, paddr, size, prot, gfp, ++ &mapped); + /* + * Some pages may have been mapped, even if an error occurred, + * so we should account for those so they can be unmapped. +@@ -2487,11 +2508,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, return -EINVAL; ret = __iommu_map(domain, iova, paddr, size, prot, gfp); @@ -101758,7 +105185,7 @@ index 58e7d03fc27c..f98a8f13ecbe 100644 return ret; -@@ -2614,11 +2611,8 @@ ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, +@@ -2625,11 +2643,8 @@ ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, sg = sg_next(sg); } @@ -101773,7 +105200,7 @@ index 58e7d03fc27c..f98a8f13ecbe 100644 out_err: diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig -index e0408e9016b9..023a963012f7 100644 +index 6ffcdad8b131..81c3c771e45d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -152,6 +152,14 @@ config I8259 @@ -101792,7 +105219,7 @@ index e0408e9016b9..023a963012f7 100644 bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile -index 246aa0603d6e..a9f13a66b191 100644 +index 787206e166fc..a50d2258371b 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o @@ -102466,34 +105893,6 @@ index 7bfe40a6bfdd..def1bc25194f 100644 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) { state = gpiod_get_value_cansleep(led_dat->gpiod); if (state < 0) -diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c -index 2b3bf1353b70..4e3936a39d0e 100644 ---- a/drivers/leds/leds-pwm.c -+++ b/drivers/leds/leds-pwm.c -@@ -54,7 +54,7 @@ static int led_pwm_set(struct led_classdev *led_cdev, - - led_dat->pwmstate.duty_cycle = duty; - led_dat->pwmstate.enabled = true; -- return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate); -+ return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); - } - - __attribute__((nonnull)) -diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c -index 46cd062b8b24..e1a81e0109e8 100644 ---- a/drivers/leds/rgb/leds-pwm-multicolor.c -+++ b/drivers/leds/rgb/leds-pwm-multicolor.c -@@ -51,8 +51,8 @@ static int led_pwm_mc_set(struct led_classdev *cdev, - - priv->leds[i].state.duty_cycle = duty; - priv->leds[i].state.enabled = duty > 0; -- ret = pwm_apply_state(priv->leds[i].pwm, -- &priv->leds[i].state); -+ ret = pwm_apply_might_sleep(priv->leds[i].pwm, -+ &priv->leds[i].state); - if (ret) - break; - } diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 2a57328eca20..6100c9690734 100644 --- a/drivers/leds/trigger/Kconfig @@ -102801,7 +106200,7 @@ index 000000000000..8a974a355656 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c -index fbfd0202047c..7e0d62fbc83e 100644 +index ea12fb8d2401..8c54980b4b7e 100644 --- a/drivers/mailbox/bcm2835-mailbox.c +++ b/drivers/mailbox/bcm2835-mailbox.c @@ -45,12 +45,15 @@ @@ -102826,10 +106225,10 @@ index fbfd0202047c..7e0d62fbc83e 100644 - ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0), + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), - bcm2835_mbox_irq, 0, dev_name(dev), mbox); + bcm2835_mbox_irq, IRQF_NO_SUSPEND, dev_name(dev), + mbox); if (ret) { - dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n", -@@ -192,7 +195,18 @@ static struct platform_driver bcm2835_mbox_driver = { +@@ -193,7 +196,18 @@ static struct platform_driver bcm2835_mbox_driver = { }, .probe = bcm2835_mbox_probe, }; @@ -102850,7 +106249,7 @@ index fbfd0202047c..7e0d62fbc83e 100644 MODULE_AUTHOR("Lubomir Rintel "); MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c -index 468191438849..33c39d5daa46 100644 +index 29bfc2bf796b..0a34ad9d9ce4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2229,12 +2229,12 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, @@ -102892,7 +106291,7 @@ index 468191438849..33c39d5daa46 100644 if (ret < 0) { dprintk(q, 3, "buffer %d, plane %d failed to export (%d)\n", diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 53b443be5a59..ba7bdf78e268 100644 +index 53b443be5a59..388906984e06 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -50,6 +50,28 @@ config VIDEO_AR0521 @@ -102924,7 +106323,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" help -@@ -201,6 +223,43 @@ config VIDEO_IMX415 +@@ -201,6 +223,55 @@ config VIDEO_IMX415 To compile this driver as a module, choose M here: the module will be called imx415. @@ -102941,6 +106340,18 @@ index 53b443be5a59..ba7bdf78e268 100644 + To compile this driver as a module, choose M here: the + module will be called imx477. + ++config VIDEO_IMX500 ++ tristate "Sony IMX500 sensor support" ++ depends on I2C && VIDEO_DEV ++ select VIDEO_V4L2_SUBDEV_API ++ select V4L2_CCI_I2C ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX500 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called IMX500. ++ +config VIDEO_IMX519 + tristate "Arducam IMX519 sensor support" + depends on I2C && VIDEO_DEV @@ -102968,7 +106379,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_MAX9271_LIB tristate -@@ -312,6 +371,16 @@ config VIDEO_OV13B10 +@@ -312,6 +383,16 @@ config VIDEO_OV13B10 This is a Video4Linux2 sensor driver for the OmniVision OV13B10 camera. @@ -102985,7 +106396,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" help -@@ -445,6 +514,20 @@ config VIDEO_OV5695 +@@ -445,6 +526,20 @@ config VIDEO_OV5695 To compile this driver as a module, choose M here: the module will be called ov5695. @@ -103006,7 +106417,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_OV6650 tristate "OmniVision OV6650 sensor support" help -@@ -621,6 +704,13 @@ endif +@@ -621,6 +716,13 @@ endif menu "Lens drivers" visible if MEDIA_CAMERA_SUPPORT @@ -103020,7 +106431,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_AD5820 tristate "AD5820 lens voice coil support" depends on GPIOLIB && I2C && VIDEO_DEV -@@ -642,6 +732,19 @@ config VIDEO_AK7375 +@@ -642,6 +744,19 @@ config VIDEO_AK7375 capability. This is designed for linear control of voice coil motors, controlled via I2C serial interface. @@ -103040,7 +106451,7 @@ index 53b443be5a59..ba7bdf78e268 100644 config VIDEO_DW9714 tristate "DW9714 lens voice coil support" depends on I2C && VIDEO_DEV -@@ -1206,6 +1309,18 @@ config VIDEO_TW9910 +@@ -1206,6 +1321,18 @@ config VIDEO_TW9910 To compile this driver as a module, choose M here: the module will be called tw9910. @@ -103060,7 +106471,7 @@ index 53b443be5a59..ba7bdf78e268 100644 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_DEV && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile -index 80b00d39b48f..40132cf56ad9 100644 +index 80b00d39b48f..4159a6504624 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -3,6 +3,7 @@ @@ -103084,11 +106495,12 @@ index 80b00d39b48f..40132cf56ad9 100644 obj-$(CONFIG_VIDEO_CCS) += ccs/ obj-$(CONFIG_VIDEO_CCS_PLL) += ccs-pll.o obj-$(CONFIG_VIDEO_CS3308) += cs3308.o -@@ -53,7 +57,11 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o +@@ -53,7 +57,12 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_IMX415) += imx415.o +obj-$(CONFIG_VIDEO_IMX477) += imx477.o ++obj-$(CONFIG_VIDEO_IMX500) += imx500.o +obj-$(CONFIG_VIDEO_IMX519) += imx519.o +obj-$(CONFIG_VIDEO_IMX708) += imx708.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o @@ -103096,7 +106508,7 @@ index 80b00d39b48f..40132cf56ad9 100644 obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o obj-$(CONFIG_VIDEO_LM3560) += lm3560.o -@@ -77,6 +85,7 @@ obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o +@@ -77,6 +86,7 @@ obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o obj-$(CONFIG_VIDEO_OV08X40) += ov08x40.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_OV13B10) += ov13b10.o @@ -103104,7 +106516,7 @@ index 80b00d39b48f..40132cf56ad9 100644 obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o -@@ -91,6 +100,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +@@ -91,6 +101,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o obj-$(CONFIG_VIDEO_OV5675) += ov5675.o obj-$(CONFIG_VIDEO_OV5693) += ov5693.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o @@ -108537,7 +111949,7 @@ index 4148009e0e01..2362c4813f5e 100644 static const struct dev_pm_ops dw9807_pm_ops = { diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c -index 3afa3f79c8a2..aeab1a8cca94 100644 +index a9a8cd148f4f..91854f16c5b9 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -77,7 +77,7 @@ @@ -113080,6 +116492,3239 @@ index 000000000000..dce7f2b4fa57 +MODULE_AUTHOR("Naushir Patuck "); +MODULE_DESCRIPTION("Sony IMX477 sensor driver"); +MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/i2c/imx500.c b/drivers/media/i2c/imx500.c +new file mode 100644 +index 000000000000..15e7d3f7dccd +--- /dev/null ++++ b/drivers/media/i2c/imx500.c +@@ -0,0 +1,3227 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Sony IMX500 cameras. ++ * Copyright (C) 2024, Raspberry Pi Ltd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Chip ID */ ++#define IMX500_REG_CHIP_ID CCI_REG16(0x0016) ++#define IMX500_CHIP_ID 0x0500 ++ ++#define IMX500_REG_MODE_SELECT CCI_REG8(0x0100) ++#define IMX500_MODE_STANDBY 0x00 ++#define IMX500_MODE_STREAMING 0x01 ++ ++#define IMX500_REG_IMAGE_ONLY_MODE CCI_REG8(0xa700) ++#define IMX500_IMAGE_ONLY_FALSE 0x00 ++#define IMX500_IMAGE_ONLY_TRUE 0x01 ++ ++#define IMX500_REG_ORIENTATION CCI_REG8(0x101) ++ ++#define IMX500_XCLK_FREQ 24000000 ++ ++#define IMX500_DEFAULT_LINK_FREQ 444000000 ++ ++#define IMX500_PIXEL_RATE 744000000 ++ ++/* V_TIMING internal */ ++#define IMX500_REG_FRAME_LENGTH CCI_REG16(0x0340) ++#define IMX500_FRAME_LENGTH_MAX 0xffdc ++#define IMX500_VBLANK_MIN 1117 ++ ++/* H_TIMING internal */ ++#define IMX500_REG_LINE_LENGTH CCI_REG16(0x0342) ++#define IMX500_LINE_LENGTH_MAX 0xfff0 ++ ++/* Long exposure multiplier */ ++#define IMX500_LONG_EXP_SHIFT_MAX 7 ++#define IMX500_LONG_EXP_SHIFT_REG CCI_REG8(0x3210) ++ ++/* Exposure control */ ++#define IMX500_REG_EXPOSURE CCI_REG16(0x0202) ++#define IMX500_EXPOSURE_OFFSET 22 ++#define IMX500_EXPOSURE_MIN 8 ++#define IMX500_EXPOSURE_STEP 1 ++#define IMX500_EXPOSURE_DEFAULT 0x640 ++#define IMX500_EXPOSURE_MAX (IMX500_FRAME_LENGTH_MAX - IMX500_EXPOSURE_OFFSET) ++ ++/* Analog gain control */ ++#define IMX500_REG_ANALOG_GAIN CCI_REG16(0x0204) ++#define IMX500_ANA_GAIN_MIN 0 ++#define IMX500_ANA_GAIN_MAX 978 ++#define IMX500_ANA_GAIN_STEP 1 ++#define IMX500_ANA_GAIN_DEFAULT 0x0 ++ ++/* Inference windows */ ++#define IMX500_REG_DWP_AP_VC_VOFF CCI_REG16(0xD500) ++#define IMX500_REG_DWP_AP_VC_HOFF CCI_REG16(0xD502) ++#define IMX500_REG_DWP_AP_VC_VSIZE CCI_REG16(0xD504) ++#define IMX500_REG_DWP_AP_VC_HSIZE CCI_REG16(0xD506) ++ ++#define IMX500_REG_DD_CH06_X_OUT_SIZE \ ++ CCI_REG16(0x3054) /* Output pixel count for KPI */ ++#define IMX500_REG_DD_CH07_X_OUT_SIZE \ ++ CCI_REG16(0x3056) /* Output pixel count for Input Tensor */ ++#define IMX500_REG_DD_CH08_X_OUT_SIZE \ ++ CCI_REG16(0x3058) /* Output pixel count for Output Tensor */ ++#define IMX500_REG_DD_CH09_X_OUT_SIZE \ ++ CCI_REG16(0x305A) /* Output pixel count for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_Y_OUT_SIZE \ ++ CCI_REG16(0x305C) /* Output line count for KPI */ ++#define IMX500_REG_DD_CH07_Y_OUT_SIZE \ ++ CCI_REG16(0x305E) /* Output line count for Input Tensor */ ++#define IMX500_REG_DD_CH08_Y_OUT_SIZE \ ++ CCI_REG16(0x3060) /* Output line count for Output Tensor */ ++#define IMX500_REG_DD_CH09_Y_OUT_SIZE \ ++ CCI_REG16(0x3062) /* Output line count for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_VCID \ ++ CCI_REG8(0x3064) /* Virtual channel ID for KPI */ ++#define IMX500_REG_DD_CH07_VCID \ ++ CCI_REG8(0x3065) /* Virtual channel ID for Input Tensor */ ++#define IMX500_REG_DD_CH08_VCID \ ++ CCI_REG8(0x3066) /* Virtual channel ID for Output Tensor */ ++#define IMX500_REG_DD_CH09_VCID \ ++ CCI_REG8(0x3067) /* Virtual channel ID for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_DT CCI_REG8(0x3068) /* Data Type for KPI */ ++#define IMX500_REG_DD_CH07_DT CCI_REG8(0x3069) /* Data Type for Input Tensor */ ++#define IMX500_REG_DD_CH08_DT CCI_REG8(0x306A) /* Data Type for Output Tensor */ ++#define IMX500_REG_DD_CH09_DT CCI_REG8(0x306B) /* Data Type for PQ Settings */ ++ ++#define IMX500_REG_DD_CH06_PACKING \ ++ CCI_REG8(0x306C) /* Pixel/byte packing for KPI */ ++#define IMX500_REG_DD_CH07_PACKING \ ++ CCI_REG8(0x306D) /* Pixel/byte packing for Input Tensor */ ++#define IMX500_REG_DD_CH08_PACKING \ ++ CCI_REG8(0x306E) /* Pixel/byte packing for Output Tensor */ ++#define IMX500_REG_DD_CH09_PACKING \ ++ CCI_REG8(0x306F) /* Pixel/byte packing for PQ Settings */ ++#define IMX500_DD_PACKING_8BPP 2 /* 8 bits/pixel */ ++#define IMX500_DD_PACKING_10BPP 3 /* 10 bits/pixel */ ++ ++/* Interrupt command (start processing command inside IMX500 CPU) */ ++#define IMX500_REG_DD_CMD_INT CCI_REG8(0x3080) ++#define IMX500_DD_CMD_INT_ST_TRANS 0 ++#define IMX500_DD_CMD_INT_UPDATE 1 ++#define IMX500_DD_CMD_INT_FLASH_ERASE 2 ++ ++/* State transition command type */ ++#define IMX500_REG_DD_ST_TRANS_CMD CCI_REG8(0xD000) ++#define IMX500_DD_ST_TRANS_CMD_LOADER_FW 0 ++#define IMX500_DD_ST_TRANS_CMD_MAIN_FW 1 ++#define IMX500_DD_ST_TRANS_CMD_NW_WEIGHTS 2 ++#define IMX500_DD_ST_TRANS_CMD_CLEAR_WEIGHTS 3 ++ ++/* Network weights update command */ ++#define IMX500_REG_DD_UPDATE_CMD CCI_REG8(0xD001) ++#define IMX500_DD_UPDATE_CMD_SRAM 0 ++#define IMX500_DD_UPDATE_CMD_FLASH 1 ++ ++/* Transfer source when loading into RAM */ ++#define IMX500_REG_DD_LOAD_MODE CCI_REG8(0xD002) ++#define IMX500_DD_LOAD_MODE_AP 0 ++#define IMX500_DD_LOAD_MODE_FLASH 1 ++ ++/* Image type to transfer */ ++#define IMX500_REG_DD_IMAGE_TYPE CCI_REG8(0xD003) ++#define IMX500_DD_IMAGE_TYPE_LOADER_FW 0 ++#define IMX500_DD_IMAGE_TYPE_MAIN_FW 1 ++#define IMX500_DD_IMAGE_TYPE_NETWORK_WEIGHTS 2 ++ ++/* Number of divisions of download image file */ ++#define IMX500_REG_DD_DOWNLOAD_DIV_NUM CCI_REG8(0xD004) ++ ++#define IMX500_REG_DD_FLASH_TYPE CCI_REG8(0xD005) ++ ++/* total size of download file (4-byte) */ ++#define IMX500_REG_DD_DOWNLOAD_FILE_SIZE CCI_REG32(0xD008) ++ ++/* Status notification (4-byte) */ ++#define IMX500_REG_DD_REF_STS CCI_REG32(0xD010) ++#define IMX500_DD_REF_STS_FATAL 0xFF ++#define IMX500_DD_REF_STS_DETECT_CNT 0xFF00 ++#define IMX500_DD_REF_STS_ERR_CNT 0xFF0000 ++#define IMX500_DD_REF_CMD_REPLY_CNT 0xFF000000 ++ ++/* Command reply status */ ++#define IMX500_REG_DD_CMD_REPLY_STS CCI_REG8(0xD014) ++#define IMX500_DD_CMD_REPLY_STS_TRANS_READY 0x00 ++#define IMX500_DD_CMD_REPLY_STS_TRANS_DONE 0x01 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_READY 0x10 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_DONE 0x11 ++#define IMX500_DD_CMD_REPLY_STS_UPDATE_CANCEL_DONE 0x12 ++#define IMX500_DD_CMD_REPLY_STS_STATUS_ERROR 0xFF ++#define IMX500_DD_CMD_REPLY_STS_MAC_AUTH_ERROR 0xFE ++#define IMX500_DD_CMD_REPLY_STS_TIMEOUT_ERROR 0xFD ++#define IMX500_DD_CMD_REPLY_STS_PARAMETER_ERROR 0xFC ++#define IMX500_DD_CMD_REPLY_STS_INTERNAL_ERROR 0xFB ++#define IMX500_DD_CMD_REPLY_STS_PACKET_FMT_ERROR 0xFA ++ ++/* Download status */ ++#define IMX500_REG_DD_DOWNLOAD_STS CCI_REG8(0xD015) ++#define IMX500_DD_DOWNLOAD_STS_READY 0 ++#define IMX500_DD_DOWNLOAD_STS_DOWNLOADING 1 ++ ++/* Update cancel */ ++#define IMX500_REG_DD_UPDATE_CANCEL CCI_REG8(0xD016) ++#define IMX500_DD_UPDATE_CANCEL_NOT_CANCEL 0 ++#define IMX500_DD_UPDATE_CANCEL_DO_CANCEL 1 ++ ++/* Notify error status */ ++#define IMX500_REG_DD_ERR_STS CCI_REG8(0xD020) ++#define IMX500_DD_ERR_STS_STATUS_ERROR_BIT 0x1 ++#define IMX500_DD_ERR_STS_INTERNAL_ERROR_BIT 0x2 ++#define IMX500_DD_ERR_STS_PARAMETER_ERROR_BIT 0x4 ++ ++/* System state */ ++#define IMX500_REG_DD_SYS_STATE CCI_REG8(0xD02A) ++#define IMX500_DD_SYS_STATE_STANDBY_NO_NETWORK 0 ++#define IMX500_DD_SYS_STATE_STEAMING_NO_NETWORK 1 ++#define IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK 2 ++#define IMX500_DD_SYS_STATE_STREAMING_WITH_NETWORK 3 ++ ++#define IMX500_REG_MAIN_FW_VERSION CCI_REG32(0xD07C) ++ ++/* Colour balance controls */ ++#define IMX500_REG_COLOUR_BALANCE_R CCI_REG16(0xd804) ++#define IMX500_REG_COLOUR_BALANCE_GR CCI_REG16(0xd806) ++#define IMX500_REG_COLOUR_BALANCE_GB CCI_REG16(0xd808) ++#define IMX500_REG_COLOUR_BALANCE_B CCI_REG16(0xd80a) ++#define IMX500_COLOUR_BALANCE_MIN 0x0001 ++#define IMX500_COLOUR_BALANCE_MAX 0x0fff ++#define IMX500_COLOUR_BALANCE_STEP 0x0001 ++#define IMX500_COLOUR_BALANCE_DEFAULT 0x0100 ++ ++/* Embedded sizes */ ++#define IMX500_MAX_EMBEDDED_SIZE \ ++ (2 * ((((IMX500_PIXEL_ARRAY_WIDTH * 10) >> 3) + 15) & ~15)) ++ ++/* Inference sizes */ ++#define IMX500_INFERENCE_LINE_WIDTH 2560 ++#define IMX500_NUM_KPI_LINES 1 ++#define IMX500_NUM_PQ_LINES 1 ++ ++/* IMX500 native and active pixel array size. */ ++#define IMX500_NATIVE_WIDTH 4072U ++#define IMX500_NATIVE_HEIGHT 3176U ++#define IMX500_PIXEL_ARRAY_LEFT 8U ++#define IMX500_PIXEL_ARRAY_TOP 16U ++#define IMX500_PIXEL_ARRAY_WIDTH 4056U ++#define IMX500_PIXEL_ARRAY_HEIGHT 3040U ++ ++enum pad_types { IMAGE_PAD, METADATA_PAD, NUM_PADS }; ++ ++#define V4L2_CID_USER_IMX500_INFERENCE_WINDOW (V4L2_CID_USER_IMX500_BASE + 0) ++#define V4L2_CID_USER_IMX500_NETWORK_FW_FD (V4L2_CID_USER_IMX500_BASE + 1) ++ ++#define ONE_MIB (1024 * 1024) ++ ++/* regulator supplies */ ++static const char *const imx500_supply_name[] = { ++ /* Supplies can be enabled in any order */ ++ "vana", /* Analog (2.7V) supply */ ++ "vdig", /* Digital Core (0.84V) supply */ ++ "vif", /* Interface (1.8V) supply */ ++}; ++ ++#define IMX500_NUM_SUPPLIES ARRAY_SIZE(imx500_supply_name) ++ ++enum imx500_image_type { ++ TYPE_LOADER = 0, ++ TYPE_MAIN = 1, ++ TYPE_NW_WEIGHTS = 2, ++ TYPE_MAX ++}; ++ ++struct imx500_reg_list { ++ unsigned int num_of_regs; ++ const struct cci_reg_sequence *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct imx500_mode { ++ /* Frame width */ ++ unsigned int width; ++ ++ /* Frame height */ ++ unsigned int height; ++ ++ /* H-timing in pixels */ ++ unsigned int line_length_pix; ++ ++ /* Analog crop rectangle. */ ++ struct v4l2_rect crop; ++ ++ /* Default register values */ ++ struct imx500_reg_list reg_list; ++}; ++ ++static const struct cci_reg_sequence mode_common_regs[] = { ++ { CCI_REG8(0x0305), 0x02 }, ++ { CCI_REG8(0x0306), 0x00 }, ++ { CCI_REG8(0x030d), 0x02 }, ++ { CCI_REG8(0x030e), 0x00 }, ++ { CCI_REG8(0x0106), 0x01 }, /* FAST_STANDBY_CTL */ ++ { CCI_REG8(0x0136), 0x1b }, /* EXCLK_FREQ */ ++ { CCI_REG8(0x0137), 0x00 }, ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, /* CSI_LANE_MODE */ ++ { CCI_REG16(0x3054), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x3056), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x3058), IMX500_INFERENCE_LINE_WIDTH }, ++ { CCI_REG16(0x305A), IMX500_INFERENCE_LINE_WIDTH }, /* X_OUT */ ++ { CCI_REG16(0x305C), IMX500_NUM_KPI_LINES }, /* KPI Y_OUT */ ++ { CCI_REG16(0x3062), IMX500_NUM_PQ_LINES }, /* PQ Y_OUT */ ++ { CCI_REG8(0x3068), 0x30 }, ++ { CCI_REG8(0x3069), 0x31 }, ++ { CCI_REG8(0x306A), 0x32 }, ++ { CCI_REG8(0x306B), 0x33 }, /* Data Types */ ++}; ++ ++/* 12 mpix 15fps */ ++static const struct cci_reg_sequence mode_4056x3040_regs[] = { ++ { CCI_REG8(0x0340), 0x12 }, ++ { CCI_REG8(0x0341), 0x42 }, ++ { CCI_REG8(0x0342), 0x45 }, ++ { CCI_REG8(0x0343), 0xec }, ++ { CCI_REG8(0x3210), 0x00 }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x0f }, ++ { CCI_REG8(0x0349), 0xd7 }, ++ { CCI_REG8(0x0350), 0x00 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0xdf }, ++ { CCI_REG8(0x3f58), 0x01 }, ++ { CCI_REG8(0x0381), 0x01 }, ++ { CCI_REG8(0x0383), 0x01 }, ++ { CCI_REG8(0x0385), 0x01 }, ++ { CCI_REG8(0x0387), 0x01 }, ++ { CCI_REG8(0x0900), 0x00 }, ++ { CCI_REG8(0x0901), 0x11 }, ++ { CCI_REG8(0x0902), 0x00 }, ++ { CCI_REG8(0x3241), 0x11 }, ++ { CCI_REG8(0x3242), 0x01 }, ++ { CCI_REG8(0x3250), 0x00 }, ++ { CCI_REG8(0x3f0f), 0x00 }, ++ { CCI_REG8(0x3f40), 0x00 }, ++ { CCI_REG8(0x3f41), 0x00 }, ++ { CCI_REG8(0x3f42), 0x00 }, ++ { CCI_REG8(0x3f43), 0x00 }, ++ { CCI_REG8(0xb34e), 0x00 }, ++ { CCI_REG8(0xb351), 0x20 }, ++ { CCI_REG8(0xb35c), 0x00 }, ++ { CCI_REG8(0xb35e), 0x08 }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x0f }, ++ { CCI_REG8(0x040d), 0xd8 }, ++ { CCI_REG8(0x040e), 0x0b }, ++ { CCI_REG8(0x040f), 0xe0 }, ++ { CCI_REG8(0x034c), 0x0f }, ++ { CCI_REG8(0x034d), 0xd8 }, ++ { CCI_REG8(0x034e), 0x0b }, ++ { CCI_REG8(0x034f), 0xe0 }, ++ { CCI_REG8(0x0301), 0x05 }, ++ { CCI_REG8(0x0303), 0x02 }, ++ { CCI_REG8(0x0307), 0x9b }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x01 }, ++ { CCI_REG8(0x030f), 0x4a }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xce }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e35), 0x01 }, ++ { CCI_REG8(0x3e36), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3a), 0x01 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x00e3), 0x00 }, ++ { CCI_REG8(0x00e4), 0x00 }, ++ { CCI_REG8(0x00e6), 0x00 }, ++ { CCI_REG8(0x00e7), 0x00 }, ++ { CCI_REG8(0x00e8), 0x00 }, ++ { CCI_REG8(0x00e9), 0x00 }, ++ { CCI_REG8(0x3f50), 0x00 }, ++ { CCI_REG8(0x3f56), 0x02 }, ++ { CCI_REG8(0x3f57), 0x42 }, ++ { CCI_REG8(0x3606), 0x01 }, ++ { CCI_REG8(0x3607), 0x01 }, ++ { CCI_REG8(0x3f26), 0x00 }, ++ { CCI_REG8(0x3f4a), 0x00 }, ++ { CCI_REG8(0x3f4b), 0x00 }, ++ { CCI_REG8(0x4bc0), 0x16 }, ++ { CCI_REG8(0x7ba8), 0x00 }, ++ { CCI_REG8(0x7ba9), 0x00 }, ++ { CCI_REG8(0x886b), 0x00 }, ++ { CCI_REG8(0x579a), 0x00 }, ++ { CCI_REG8(0x579b), 0x0a }, ++ { CCI_REG8(0x579c), 0x01 }, ++ { CCI_REG8(0x579d), 0x2a }, ++ { CCI_REG8(0x57ac), 0x00 }, ++ { CCI_REG8(0x57ad), 0x00 }, ++ { CCI_REG8(0x57ae), 0x00 }, ++ { CCI_REG8(0x57af), 0x81 }, ++ { CCI_REG8(0x57be), 0x00 }, ++ { CCI_REG8(0x57bf), 0x00 }, ++ { CCI_REG8(0x57c0), 0x00 }, ++ { CCI_REG8(0x57c1), 0x81 }, ++ { CCI_REG8(0x57d0), 0x00 }, ++ { CCI_REG8(0x57d1), 0x00 }, ++ { CCI_REG8(0x57d2), 0x00 }, ++ { CCI_REG8(0x57d3), 0x81 }, ++ { CCI_REG8(0x5324), 0x00 }, ++ { CCI_REG8(0x5325), 0x26 }, ++ { CCI_REG8(0x5326), 0x00 }, ++ { CCI_REG8(0x5327), 0x6b }, ++ { CCI_REG8(0xbca7), 0x00 }, ++ { CCI_REG8(0x5fcc), 0x28 }, ++ { CCI_REG8(0x5fd7), 0x2d }, ++ { CCI_REG8(0x5fe2), 0x2d }, ++ { CCI_REG8(0x5fed), 0x2d }, ++ { CCI_REG8(0x5ff8), 0x2d }, ++ { CCI_REG8(0x6003), 0x2d }, ++ { CCI_REG8(0x5d0b), 0x01 }, ++ { CCI_REG8(0x6f6d), 0x00 }, ++ { CCI_REG8(0x61c9), 0x00 }, ++ { CCI_REG8(0x5352), 0x00 }, ++ { CCI_REG8(0x5353), 0x49 }, ++ { CCI_REG8(0x5356), 0x00 }, ++ { CCI_REG8(0x5357), 0x30 }, ++ { CCI_REG8(0x5358), 0x00 }, ++ { CCI_REG8(0x5359), 0x3b }, ++ { CCI_REG8(0x535c), 0x00 }, ++ { CCI_REG8(0x535d), 0xb0 }, ++ { CCI_REG8(0x6187), 0x18 }, ++ { CCI_REG8(0x6189), 0x18 }, ++ { CCI_REG8(0x618b), 0x18 }, ++ { CCI_REG8(0x618d), 0x1d }, ++ { CCI_REG8(0x618f), 0x1d }, ++ { CCI_REG8(0x5414), 0x01 }, ++ { CCI_REG8(0x5415), 0x0c }, ++ { CCI_REG8(0xbca8), 0x0a }, ++ { CCI_REG8(0x5fcf), 0x1e }, ++ { CCI_REG8(0x5fda), 0x1e }, ++ { CCI_REG8(0x5fe5), 0x1e }, ++ { CCI_REG8(0x5ff0), 0x1e }, ++ { CCI_REG8(0x5ffb), 0x1e }, ++ { CCI_REG8(0x6006), 0x1e }, ++ { CCI_REG8(0x616e), 0x04 }, ++ { CCI_REG8(0x616f), 0x04 }, ++ { CCI_REG8(0x6170), 0x04 }, ++ { CCI_REG8(0x6171), 0x06 }, ++ { CCI_REG8(0x6172), 0x06 }, ++ { CCI_REG8(0x6173), 0x0c }, ++ { CCI_REG8(0x6174), 0x0c }, ++ { CCI_REG8(0x6175), 0x0c }, ++ { CCI_REG8(0x6176), 0x00 }, ++ { CCI_REG8(0x6177), 0x10 }, ++ { CCI_REG8(0x6178), 0x00 }, ++ { CCI_REG8(0x6179), 0x1a }, ++ { CCI_REG8(0x617a), 0x00 }, ++ { CCI_REG8(0x617b), 0x1a }, ++ { CCI_REG8(0x617c), 0x00 }, ++ { CCI_REG8(0x617d), 0x27 }, ++ { CCI_REG8(0x617e), 0x00 }, ++ { CCI_REG8(0x617f), 0x27 }, ++ { CCI_REG8(0x6180), 0x00 }, ++ { CCI_REG8(0x6181), 0x44 }, ++ { CCI_REG8(0x6182), 0x00 }, ++ { CCI_REG8(0x6183), 0x44 }, ++ { CCI_REG8(0x6184), 0x00 }, ++ { CCI_REG8(0x6185), 0x44 }, ++ { CCI_REG8(0x5dfc), 0x0a }, ++ { CCI_REG8(0x5e00), 0x0a }, ++ { CCI_REG8(0x5e04), 0x0a }, ++ { CCI_REG8(0x5e08), 0x0a }, ++ { CCI_REG8(0x5dfd), 0x0a }, ++ { CCI_REG8(0x5e01), 0x0a }, ++ { CCI_REG8(0x5e05), 0x0a }, ++ { CCI_REG8(0x5e09), 0x0a }, ++ { CCI_REG8(0x5dfe), 0x0a }, ++ { CCI_REG8(0x5e02), 0x0a }, ++ { CCI_REG8(0x5e06), 0x0a }, ++ { CCI_REG8(0x5e0a), 0x0a }, ++ { CCI_REG8(0x5dff), 0x0a }, ++ { CCI_REG8(0x5e03), 0x0a }, ++ { CCI_REG8(0x5e07), 0x0a }, ++ { CCI_REG8(0x5e0b), 0x0a }, ++ { CCI_REG8(0x5dec), 0x12 }, ++ { CCI_REG8(0x5df0), 0x12 }, ++ { CCI_REG8(0x5df4), 0x21 }, ++ { CCI_REG8(0x5df8), 0x31 }, ++ { CCI_REG8(0x5ded), 0x12 }, ++ { CCI_REG8(0x5df1), 0x12 }, ++ { CCI_REG8(0x5df5), 0x21 }, ++ { CCI_REG8(0x5df9), 0x31 }, ++ { CCI_REG8(0x5dee), 0x12 }, ++ { CCI_REG8(0x5df2), 0x12 }, ++ { CCI_REG8(0x5df6), 0x21 }, ++ { CCI_REG8(0x5dfa), 0x31 }, ++ { CCI_REG8(0x5def), 0x12 }, ++ { CCI_REG8(0x5df3), 0x12 }, ++ { CCI_REG8(0x5df7), 0x21 }, ++ { CCI_REG8(0x5dfb), 0x31 }, ++ { CCI_REG8(0x5ddc), 0x0d }, ++ { CCI_REG8(0x5de0), 0x0d }, ++ { CCI_REG8(0x5de4), 0x0d }, ++ { CCI_REG8(0x5de8), 0x0d }, ++ { CCI_REG8(0x5ddd), 0x0d }, ++ { CCI_REG8(0x5de1), 0x0d }, ++ { CCI_REG8(0x5de5), 0x0d }, ++ { CCI_REG8(0x5de9), 0x0d }, ++ { CCI_REG8(0x5dde), 0x0d }, ++ { CCI_REG8(0x5de2), 0x0d }, ++ { CCI_REG8(0x5de6), 0x0d }, ++ { CCI_REG8(0x5dea), 0x0d }, ++ { CCI_REG8(0x5ddf), 0x0d }, ++ { CCI_REG8(0x5de3), 0x0d }, ++ { CCI_REG8(0x5de7), 0x0d }, ++ { CCI_REG8(0x5deb), 0x0d }, ++ { CCI_REG8(0x5dcc), 0x55 }, ++ { CCI_REG8(0x5dd0), 0x50 }, ++ { CCI_REG8(0x5dd4), 0x4b }, ++ { CCI_REG8(0x5dd8), 0x4b }, ++ { CCI_REG8(0x5dcd), 0x55 }, ++ { CCI_REG8(0x5dd1), 0x50 }, ++ { CCI_REG8(0x5dd5), 0x4b }, ++ { CCI_REG8(0x5dd9), 0x4b }, ++ { CCI_REG8(0x5dce), 0x55 }, ++ { CCI_REG8(0x5dd2), 0x50 }, ++ { CCI_REG8(0x5dd6), 0x4b }, ++ { CCI_REG8(0x5dda), 0x4b }, ++ { CCI_REG8(0x5dcf), 0x55 }, ++ { CCI_REG8(0x5dd3), 0x50 }, ++ { CCI_REG8(0x5dd7), 0x4b }, ++ { CCI_REG8(0x5ddb), 0x4b }, ++ { CCI_REG8(0x0202), 0x12 }, ++ { CCI_REG8(0x0203), 0x2c }, ++ { CCI_REG8(0x0204), 0x00 }, ++ { CCI_REG8(0x0205), 0x00 }, ++ { CCI_REG8(0x020e), 0x01 }, ++ { CCI_REG8(0x020f), 0x00 }, ++ { CCI_REG8(0x0210), 0x01 }, ++ { CCI_REG8(0x0211), 0x00 }, ++ { CCI_REG8(0x0212), 0x01 }, ++ { CCI_REG8(0x0213), 0x00 }, ++ { CCI_REG8(0x0214), 0x01 }, ++ { CCI_REG8(0x0215), 0x00 }, ++}; ++ ++/* 2x2 binned. 56fps */ ++static const struct cci_reg_sequence mode_2028x1520_regs[] = { ++ { CCI_REG8(0x0112), 0x0a }, ++ { CCI_REG8(0x0113), 0x0a }, ++ { CCI_REG8(0x0114), 0x01 }, ++ { CCI_REG8(0x0342), 0x24 }, ++ { CCI_REG8(0x0343), 0xb6 }, ++ { CCI_REG8(0x0340), 0x0b }, ++ { CCI_REG8(0x0341), 0x9c }, ++ { CCI_REG8(0x3210), 0x00 }, ++ { CCI_REG8(0x0344), 0x00 }, ++ { CCI_REG8(0x0345), 0x00 }, ++ { CCI_REG8(0x0346), 0x00 }, ++ { CCI_REG8(0x0347), 0x00 }, ++ { CCI_REG8(0x0348), 0x0f }, ++ { CCI_REG8(0x0349), 0xd7 }, ++ { CCI_REG8(0x0350), 0x00 }, ++ { CCI_REG8(0x034a), 0x0b }, ++ { CCI_REG8(0x034b), 0xdf }, ++ { CCI_REG8(0x3f58), 0x01 }, ++ { CCI_REG8(0x0381), 0x01 }, ++ { CCI_REG8(0x0383), 0x01 }, ++ { CCI_REG8(0x0385), 0x01 }, ++ { CCI_REG8(0x0387), 0x01 }, ++ { CCI_REG8(0x0900), 0x01 }, ++ { CCI_REG8(0x0901), 0x22 }, ++ { CCI_REG8(0x0902), 0x02 }, ++ { CCI_REG8(0x3241), 0x11 }, ++ { CCI_REG8(0x3242), 0x01 }, ++ { CCI_REG8(0x3250), 0x03 }, ++ { CCI_REG8(0x3f0f), 0x00 }, ++ { CCI_REG8(0x3f40), 0x00 }, ++ { CCI_REG8(0x3f41), 0x00 }, ++ { CCI_REG8(0x3f42), 0x00 }, ++ { CCI_REG8(0x3f43), 0x00 }, ++ { CCI_REG8(0xb34e), 0x00 }, ++ { CCI_REG8(0xb351), 0x20 }, ++ { CCI_REG8(0xb35c), 0x00 }, ++ { CCI_REG8(0xb35e), 0x08 }, ++ { CCI_REG8(0x0401), 0x00 }, ++ { CCI_REG8(0x0404), 0x00 }, ++ { CCI_REG8(0x0405), 0x10 }, ++ { CCI_REG8(0x0408), 0x00 }, ++ { CCI_REG8(0x0409), 0x00 }, ++ { CCI_REG8(0x040a), 0x00 }, ++ { CCI_REG8(0x040b), 0x00 }, ++ { CCI_REG8(0x040c), 0x07 }, ++ { CCI_REG8(0x040d), 0xec }, ++ { CCI_REG8(0x040e), 0x05 }, ++ { CCI_REG8(0x040f), 0xf0 }, ++ { CCI_REG8(0x034c), 0x07 }, ++ { CCI_REG8(0x034d), 0xec }, ++ { CCI_REG8(0x034e), 0x05 }, ++ { CCI_REG8(0x034f), 0xf0 }, ++ { CCI_REG8(0x0301), 0x05 }, ++ { CCI_REG8(0x0303), 0x02 }, ++ { CCI_REG8(0x0307), 0x9b }, ++ { CCI_REG8(0x0309), 0x0a }, ++ { CCI_REG8(0x030b), 0x01 }, ++ { CCI_REG8(0x030f), 0x4a }, ++ { CCI_REG8(0x0310), 0x01 }, ++ { CCI_REG8(0x0820), 0x07 }, ++ { CCI_REG8(0x0821), 0xce }, ++ { CCI_REG8(0x0822), 0x00 }, ++ { CCI_REG8(0x0823), 0x00 }, ++ { CCI_REG8(0x3e20), 0x01 }, ++ { CCI_REG8(0x3e35), 0x01 }, ++ { CCI_REG8(0x3e36), 0x01 }, ++ { CCI_REG8(0x3e37), 0x00 }, ++ { CCI_REG8(0x3e3a), 0x01 }, ++ { CCI_REG8(0x3e3b), 0x00 }, ++ { CCI_REG8(0x00e3), 0x00 }, ++ { CCI_REG8(0x00e4), 0x00 }, ++ { CCI_REG8(0x00e6), 0x00 }, ++ { CCI_REG8(0x00e7), 0x00 }, ++ { CCI_REG8(0x00e8), 0x00 }, ++ { CCI_REG8(0x00e9), 0x00 }, ++ { CCI_REG8(0x3f50), 0x00 }, ++ { CCI_REG8(0x3f56), 0x01 }, ++ { CCI_REG8(0x3f57), 0x30 }, ++ { CCI_REG8(0x3606), 0x01 }, ++ { CCI_REG8(0x3607), 0x01 }, ++ { CCI_REG8(0x3f26), 0x00 }, ++ { CCI_REG8(0x3f4a), 0x00 }, ++ { CCI_REG8(0x3f4b), 0x00 }, ++ { CCI_REG8(0x4bc0), 0x16 }, ++ { CCI_REG8(0x7ba8), 0x00 }, ++ { CCI_REG8(0x7ba9), 0x00 }, ++ { CCI_REG8(0x886b), 0x00 }, ++ { CCI_REG8(0x579a), 0x00 }, ++ { CCI_REG8(0x579b), 0x0a }, ++ { CCI_REG8(0x579c), 0x01 }, ++ { CCI_REG8(0x579d), 0x2a }, ++ { CCI_REG8(0x57ac), 0x00 }, ++ { CCI_REG8(0x57ad), 0x00 }, ++ { CCI_REG8(0x57ae), 0x00 }, ++ { CCI_REG8(0x57af), 0x81 }, ++ { CCI_REG8(0x57be), 0x00 }, ++ { CCI_REG8(0x57bf), 0x00 }, ++ { CCI_REG8(0x57c0), 0x00 }, ++ { CCI_REG8(0x57c1), 0x81 }, ++ { CCI_REG8(0x57d0), 0x00 }, ++ { CCI_REG8(0x57d1), 0x00 }, ++ { CCI_REG8(0x57d2), 0x00 }, ++ { CCI_REG8(0x57d3), 0x81 }, ++ { CCI_REG8(0x5324), 0x00 }, ++ { CCI_REG8(0x5325), 0x31 }, ++ { CCI_REG8(0x5326), 0x00 }, ++ { CCI_REG8(0x5327), 0x60 }, ++ { CCI_REG8(0xbca7), 0x08 }, ++ { CCI_REG8(0x5fcc), 0x1e }, ++ { CCI_REG8(0x5fd7), 0x1e }, ++ { CCI_REG8(0x5fe2), 0x1e }, ++ { CCI_REG8(0x5fed), 0x1e }, ++ { CCI_REG8(0x5ff8), 0x1e }, ++ { CCI_REG8(0x6003), 0x1e }, ++ { CCI_REG8(0x5d0b), 0x02 }, ++ { CCI_REG8(0x6f6d), 0x01 }, ++ { CCI_REG8(0x61c9), 0x68 }, ++ { CCI_REG8(0x5352), 0x00 }, ++ { CCI_REG8(0x5353), 0x3f }, ++ { CCI_REG8(0x5356), 0x00 }, ++ { CCI_REG8(0x5357), 0x1c }, ++ { CCI_REG8(0x5358), 0x00 }, ++ { CCI_REG8(0x5359), 0x3d }, ++ { CCI_REG8(0x535c), 0x00 }, ++ { CCI_REG8(0x535d), 0xa6 }, ++ { CCI_REG8(0x6187), 0x1d }, ++ { CCI_REG8(0x6189), 0x1d }, ++ { CCI_REG8(0x618b), 0x1d }, ++ { CCI_REG8(0x618d), 0x23 }, ++ { CCI_REG8(0x618f), 0x23 }, ++ { CCI_REG8(0x5414), 0x01 }, ++ { CCI_REG8(0x5415), 0x12 }, ++ { CCI_REG8(0xbca8), 0x00 }, ++ { CCI_REG8(0x5fcf), 0x28 }, ++ { CCI_REG8(0x5fda), 0x2d }, ++ { CCI_REG8(0x5fe5), 0x2d }, ++ { CCI_REG8(0x5ff0), 0x2d }, ++ { CCI_REG8(0x5ffb), 0x2d }, ++ { CCI_REG8(0x6006), 0x2d }, ++ { CCI_REG8(0x616e), 0x04 }, ++ { CCI_REG8(0x616f), 0x04 }, ++ { CCI_REG8(0x6170), 0x04 }, ++ { CCI_REG8(0x6171), 0x06 }, ++ { CCI_REG8(0x6172), 0x06 }, ++ { CCI_REG8(0x6173), 0x0c }, ++ { CCI_REG8(0x6174), 0x0c }, ++ { CCI_REG8(0x6175), 0x0c }, ++ { CCI_REG8(0x6176), 0x00 }, ++ { CCI_REG8(0x6177), 0x10 }, ++ { CCI_REG8(0x6178), 0x00 }, ++ { CCI_REG8(0x6179), 0x1a }, ++ { CCI_REG8(0x617a), 0x00 }, ++ { CCI_REG8(0x617b), 0x1a }, ++ { CCI_REG8(0x617c), 0x00 }, ++ { CCI_REG8(0x617d), 0x27 }, ++ { CCI_REG8(0x617e), 0x00 }, ++ { CCI_REG8(0x617f), 0x27 }, ++ { CCI_REG8(0x6180), 0x00 }, ++ { CCI_REG8(0x6181), 0x44 }, ++ { CCI_REG8(0x6182), 0x00 }, ++ { CCI_REG8(0x6183), 0x44 }, ++ { CCI_REG8(0x6184), 0x00 }, ++ { CCI_REG8(0x6185), 0x44 }, ++ { CCI_REG8(0x5dfc), 0x0a }, ++ { CCI_REG8(0x5e00), 0x0a }, ++ { CCI_REG8(0x5e04), 0x0a }, ++ { CCI_REG8(0x5e08), 0x0a }, ++ { CCI_REG8(0x5dfd), 0x0a }, ++ { CCI_REG8(0x5e01), 0x0a }, ++ { CCI_REG8(0x5e05), 0x0a }, ++ { CCI_REG8(0x5e09), 0x0a }, ++ { CCI_REG8(0x5dfe), 0x0a }, ++ { CCI_REG8(0x5e02), 0x0a }, ++ { CCI_REG8(0x5e06), 0x0a }, ++ { CCI_REG8(0x5e0a), 0x0a }, ++ { CCI_REG8(0x5dff), 0x0a }, ++ { CCI_REG8(0x5e03), 0x0a }, ++ { CCI_REG8(0x5e07), 0x0a }, ++ { CCI_REG8(0x5e0b), 0x0a }, ++ { CCI_REG8(0x5dec), 0x12 }, ++ { CCI_REG8(0x5df0), 0x12 }, ++ { CCI_REG8(0x5df4), 0x21 }, ++ { CCI_REG8(0x5df8), 0x31 }, ++ { CCI_REG8(0x5ded), 0x12 }, ++ { CCI_REG8(0x5df1), 0x12 }, ++ { CCI_REG8(0x5df5), 0x21 }, ++ { CCI_REG8(0x5df9), 0x31 }, ++ { CCI_REG8(0x5dee), 0x12 }, ++ { CCI_REG8(0x5df2), 0x12 }, ++ { CCI_REG8(0x5df6), 0x21 }, ++ { CCI_REG8(0x5dfa), 0x31 }, ++ { CCI_REG8(0x5def), 0x12 }, ++ { CCI_REG8(0x5df3), 0x12 }, ++ { CCI_REG8(0x5df7), 0x21 }, ++ { CCI_REG8(0x5dfb), 0x31 }, ++ { CCI_REG8(0x5ddc), 0x0d }, ++ { CCI_REG8(0x5de0), 0x0d }, ++ { CCI_REG8(0x5de4), 0x0d }, ++ { CCI_REG8(0x5de8), 0x0d }, ++ { CCI_REG8(0x5ddd), 0x0d }, ++ { CCI_REG8(0x5de1), 0x0d }, ++ { CCI_REG8(0x5de5), 0x0d }, ++ { CCI_REG8(0x5de9), 0x0d }, ++ { CCI_REG8(0x5dde), 0x0d }, ++ { CCI_REG8(0x5de2), 0x0d }, ++ { CCI_REG8(0x5de6), 0x0d }, ++ { CCI_REG8(0x5dea), 0x0d }, ++ { CCI_REG8(0x5ddf), 0x0d }, ++ { CCI_REG8(0x5de3), 0x0d }, ++ { CCI_REG8(0x5de7), 0x0d }, ++ { CCI_REG8(0x5deb), 0x0d }, ++ { CCI_REG8(0x5dcc), 0x55 }, ++ { CCI_REG8(0x5dd0), 0x50 }, ++ { CCI_REG8(0x5dd4), 0x4b }, ++ { CCI_REG8(0x5dd8), 0x4b }, ++ { CCI_REG8(0x5dcd), 0x55 }, ++ { CCI_REG8(0x5dd1), 0x50 }, ++ { CCI_REG8(0x5dd5), 0x4b }, ++ { CCI_REG8(0x5dd9), 0x4b }, ++ { CCI_REG8(0x5dce), 0x55 }, ++ { CCI_REG8(0x5dd2), 0x50 }, ++ { CCI_REG8(0x5dd6), 0x4b }, ++ { CCI_REG8(0x5dda), 0x4b }, ++ { CCI_REG8(0x5dcf), 0x55 }, ++ { CCI_REG8(0x5dd3), 0x50 }, ++ { CCI_REG8(0x5dd7), 0x4b }, ++ { CCI_REG8(0x5ddb), 0x4b }, ++ { CCI_REG8(0x0202), 0x0b }, ++ { CCI_REG8(0x0203), 0x86 }, ++ { CCI_REG8(0x0204), 0x00 }, ++ { CCI_REG8(0x0205), 0x00 }, ++ { CCI_REG8(0x020e), 0x01 }, ++ { CCI_REG8(0x020f), 0x00 }, ++ { CCI_REG8(0x0210), 0x01 }, ++ { CCI_REG8(0x0211), 0x00 }, ++ { CCI_REG8(0x0212), 0x01 }, ++ { CCI_REG8(0x0213), 0x00 }, ++ { CCI_REG8(0x0214), 0x01 }, ++ { CCI_REG8(0x0215), 0x00 }, ++}; ++ ++static const struct cci_reg_sequence metadata_output[] = { ++ { CCI_REG8(0x3050), 1 }, /* MIPI Output enabled */ ++ { CCI_REG8(0x3051), 1 }, /* MIPI output frame includes pixels data */ ++ { CCI_REG8(0x3052), 1 }, /* MIPI output frame includes meta data */ ++ { IMX500_REG_DD_CH06_VCID, 0 }, ++ { IMX500_REG_DD_CH07_VCID, 0 }, ++ { IMX500_REG_DD_CH08_VCID, 0 }, ++ { IMX500_REG_DD_CH09_VCID, 0 }, ++ { IMX500_REG_DD_CH06_DT, ++ 0x12 }, /* KPI - User Defined 8-bit Data Type 1 */ ++ { IMX500_REG_DD_CH07_DT, 0x12 }, /* Input Tensor - U.D. 8-bit type 2 */ ++ { IMX500_REG_DD_CH08_DT, 0x12 }, /* Output Tensor - U.D. 8-bit type 3 */ ++ { IMX500_REG_DD_CH09_DT, 0x12 }, /* PQ - U.D. 8-bit type 4 */ ++ { IMX500_REG_DD_CH06_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH07_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH08_PACKING, IMX500_DD_PACKING_8BPP }, ++ { IMX500_REG_DD_CH09_PACKING, IMX500_DD_PACKING_8BPP }, ++}; ++ ++static const struct cci_reg_sequence dnn_regs[] = { ++ { CCI_REG8(0xd960), 0x52 }, ++ { CCI_REG8(0xd961), 0x52 }, ++ { CCI_REG8(0xd962), 0x52 }, ++ { CCI_REG8(0xd963), 0x52 }, ++ { CCI_REG8(0xd96c), 0x44 }, ++ { CCI_REG8(0xd96d), 0x44 }, ++ { CCI_REG8(0xd96e), 0x44 }, ++ { CCI_REG8(0xd96f), 0x44 }, ++ { CCI_REG8(0xd600), 0x20 }, ++ /* Black level */ ++ { CCI_REG16(0xd80c), 0x100 }, ++ { CCI_REG16(0xd80e), 0x100 }, ++ { CCI_REG16(0xd810), 0x100 }, ++ { CCI_REG16(0xd812), 0x100 }, ++ /* Gamma */ ++ { CCI_REG8(0xd814), 1 }, ++ { CCI_REG32(0xd850), 0x10000 }, ++ { CCI_REG32(0xd854), 0x40002 }, ++ { CCI_REG32(0xd858), 0x60005 }, ++ { CCI_REG32(0xd85c), 0x90008 }, ++ { CCI_REG32(0xd860), 0xc000a }, ++ { CCI_REG32(0xd864), 0x12000f }, ++ { CCI_REG32(0xd868), 0x1c0014 }, ++ { CCI_REG32(0xd86c), 0x2a0024 }, ++ { CCI_REG32(0xd870), 0x360030 }, ++ { CCI_REG32(0xd874), 0x46003c }, ++ { CCI_REG32(0xd878), 0x5a0051 }, ++ { CCI_REG32(0xd87c), 0x750064 }, ++ { CCI_REG32(0xd880), 0x920084 }, ++ { CCI_REG32(0xd884), 0xa9009e }, ++ { CCI_REG32(0xd888), 0xba00b2 }, ++ { CCI_REG32(0xd88c), 0xc700c1 }, ++ { CCI_REG32(0xd890), 0xd100cd }, ++ { CCI_REG32(0xd894), 0xde00d6 }, ++ { CCI_REG32(0xd898), 0xe900e4 }, ++ { CCI_REG32(0xd89c), 0xf300ee }, ++ { CCI_REG32(0xd8a0), 0xfb00f7 }, ++ { CCI_REG16(0xd8a4), 0xff }, ++ { CCI_REG32(0xd8a8), 0x10000 }, ++ { CCI_REG32(0xd8ac), 0x40002 }, ++ { CCI_REG32(0xd8b0), 0x60005 }, ++ { CCI_REG32(0xd8b4), 0x90008 }, ++ { CCI_REG32(0xd8b8), 0xc000a }, ++ { CCI_REG32(0xd8bc), 0x12000f }, ++ { CCI_REG32(0xd8c0), 0x1c0014 }, ++ { CCI_REG32(0xd8c4), 0x2a0024 }, ++ { CCI_REG32(0xd8c8), 0x360030 }, ++ { CCI_REG32(0xd8cc), 0x46003c }, ++ { CCI_REG32(0xd8d0), 0x5a0051 }, ++ { CCI_REG32(0xd8d4), 0x750064 }, ++ { CCI_REG32(0xd8d8), 0x920084 }, ++ { CCI_REG32(0xd8dc), 0xa9009e }, ++ { CCI_REG32(0xd8e0), 0xba00b2 }, ++ { CCI_REG32(0xd8e4), 0xc700c1 }, ++ { CCI_REG32(0xd8e8), 0xd100cd }, ++ { CCI_REG32(0xd8ec), 0xde00d6 }, ++ { CCI_REG32(0xd8f0), 0xe900e4 }, ++ { CCI_REG32(0xd8f4), 0xf300ee }, ++ { CCI_REG32(0xd8f8), 0xfb00f7 }, ++ { CCI_REG16(0xd8fc), 0xff }, ++ { CCI_REG32(0xd900), 0x10000 }, ++ { CCI_REG32(0xd904), 0x40002 }, ++ { CCI_REG32(0xd908), 0x60005 }, ++ { CCI_REG32(0xd90c), 0x90008 }, ++ { CCI_REG32(0xd910), 0xc000a }, ++ { CCI_REG32(0xd914), 0x12000f }, ++ { CCI_REG32(0xd918), 0x1c0014 }, ++ { CCI_REG32(0xd91c), 0x2a0024 }, ++ { CCI_REG32(0xd920), 0x360030 }, ++ { CCI_REG32(0xd924), 0x46003c }, ++ { CCI_REG32(0xd928), 0x5a0051 }, ++ { CCI_REG32(0xd92c), 0x750064 }, ++ { CCI_REG32(0xd930), 0x920084 }, ++ { CCI_REG32(0xd934), 0xa9009e }, ++ { CCI_REG32(0xd938), 0xba00b2 }, ++ { CCI_REG32(0xd93c), 0xc700c1 }, ++ { CCI_REG32(0xd940), 0xd100cd }, ++ { CCI_REG32(0xd944), 0xde00d6 }, ++ { CCI_REG32(0xd948), 0xe900e4 }, ++ { CCI_REG32(0xd94c), 0xf300ee }, ++ { CCI_REG32(0xd950), 0xfb00f7 }, ++ { CCI_REG16(0xd954), 0xff }, ++ { CCI_REG8(0xd826), 1 }, ++ /* LSC */ ++ { CCI_REG32(0xe000), 0x2e502a0 }, ++ { CCI_REG32(0xe004), 0x2c80283 }, ++ { CCI_REG32(0xe008), 0x2700233 }, ++ { CCI_REG32(0xe00c), 0x22d01f6 }, ++ { CCI_REG32(0xe010), 0x1f401c3 }, ++ { CCI_REG32(0xe014), 0x1c5019c }, ++ { CCI_REG32(0xe018), 0x1bb0192 }, ++ { CCI_REG32(0xe01c), 0x1ba0192 }, ++ { CCI_REG32(0xe020), 0x1b90192 }, ++ { CCI_REG32(0xe024), 0x1ba0192 }, ++ { CCI_REG32(0xe028), 0x1ca019f }, ++ { CCI_REG32(0xe02c), 0x1fb01c8 }, ++ { CCI_REG32(0xe030), 0x23601fb }, ++ { CCI_REG32(0xe034), 0x27a0239 }, ++ { CCI_REG32(0xe038), 0x2d5028a }, ++ { CCI_REG32(0xe03c), 0x2f302a8 }, ++ { CCI_REG32(0xe040), 0x2c60283 }, ++ { CCI_REG32(0xe044), 0x27c0240 }, ++ { CCI_REG32(0xe048), 0x22d01f6 }, ++ { CCI_REG32(0xe04c), 0x1fd01cd }, ++ { CCI_REG32(0xe050), 0x1c4019c }, ++ { CCI_REG32(0xe054), 0x19c017b }, ++ { CCI_REG32(0xe058), 0x1810165 }, ++ { CCI_REG32(0xe05c), 0x175015c }, ++ { CCI_REG32(0xe060), 0x175015c }, ++ { CCI_REG32(0xe064), 0x1840167 }, ++ { CCI_REG32(0xe068), 0x1a0017e }, ++ { CCI_REG32(0xe06c), 0x1cc01a1 }, ++ { CCI_REG32(0xe070), 0x20501d1 }, ++ { CCI_REG32(0xe074), 0x23601fc }, ++ { CCI_REG32(0xe078), 0x2890246 }, ++ { CCI_REG32(0xe07c), 0x2d3028a }, ++ { CCI_REG32(0xe080), 0x2800243 }, ++ { CCI_REG32(0xe084), 0x245020e }, ++ { CCI_REG32(0xe088), 0x1ff01ce }, ++ { CCI_REG32(0xe08c), 0x1c4019c }, ++ { CCI_REG32(0xe090), 0x19a017b }, ++ { CCI_REG32(0xe094), 0x1650150 }, ++ { CCI_REG32(0xe098), 0x14a013a }, ++ { CCI_REG32(0xe09c), 0x13f0131 }, ++ { CCI_REG32(0xe0a0), 0x1400131 }, ++ { CCI_REG32(0xe0a4), 0x14d013c }, ++ { CCI_REG32(0xe0a8), 0x16a0154 }, ++ { CCI_REG32(0xe0ac), 0x1a1017e }, ++ { CCI_REG32(0xe0b0), 0x1cc01a1 }, ++ { CCI_REG32(0xe0b4), 0x20801d3 }, ++ { CCI_REG32(0xe0b8), 0x2510214 }, ++ { CCI_REG32(0xe0bc), 0x28b0249 }, ++ { CCI_REG32(0xe0c0), 0x2640229 }, ++ { CCI_REG32(0xe0c4), 0x22101ed }, ++ { CCI_REG32(0xe0c8), 0x1dc01b0 }, ++ { CCI_REG32(0xe0cc), 0x19c017c }, ++ { CCI_REG32(0xe0d0), 0x1650150 }, ++ { CCI_REG32(0xe0d4), 0x148013a }, ++ { CCI_REG32(0xe0d8), 0x123011c }, ++ { CCI_REG32(0xe0dc), 0x1190113 }, ++ { CCI_REG32(0xe0e0), 0x1190113 }, ++ { CCI_REG32(0xe0e4), 0x1280120 }, ++ { CCI_REG32(0xe0e8), 0x14c013c }, ++ { CCI_REG32(0xe0ec), 0x16b0154 }, ++ { CCI_REG32(0xe0f0), 0x1a30181 }, ++ { CCI_REG32(0xe0f4), 0x1e601b6 }, ++ { CCI_REG32(0xe0f8), 0x22c01f3 }, ++ { CCI_REG32(0xe0fc), 0x2700230 }, ++ { CCI_REG32(0xe100), 0x257021d }, ++ { CCI_REG32(0xe104), 0x20901d8 }, ++ { CCI_REG32(0xe108), 0x1c4019d }, ++ { CCI_REG32(0xe10c), 0x1820167 }, ++ { CCI_REG32(0xe110), 0x14b013b }, ++ { CCI_REG32(0xe114), 0x124011c }, ++ { CCI_REG32(0xe118), 0x1170113 }, ++ { CCI_REG32(0xe11c), 0x1010101 }, ++ { CCI_REG32(0xe120), 0x1030102 }, ++ { CCI_REG32(0xe124), 0x1190113 }, ++ { CCI_REG32(0xe128), 0x1280120 }, ++ { CCI_REG32(0xe12c), 0x14f013f }, ++ { CCI_REG32(0xe130), 0x189016c }, ++ { CCI_REG32(0xe134), 0x1ce01a3 }, ++ { CCI_REG32(0xe138), 0x21601df }, ++ { CCI_REG32(0xe13c), 0x2630224 }, ++ { CCI_REG32(0xe140), 0x257021d }, ++ { CCI_REG32(0xe144), 0x20101d0 }, ++ { CCI_REG32(0xe148), 0x1ba0194 }, ++ { CCI_REG32(0xe14c), 0x176015d }, ++ { CCI_REG32(0xe150), 0x13e0132 }, ++ { CCI_REG32(0xe154), 0x1190114 }, ++ { CCI_REG32(0xe158), 0x1010101 }, ++ { CCI_REG32(0xe15c), 0x1000100 }, ++ { CCI_REG32(0xe160), 0x1010100 }, ++ { CCI_REG32(0xe164), 0x1040103 }, ++ { CCI_REG32(0xe168), 0x11d0118 }, ++ { CCI_REG32(0xe16c), 0x1450136 }, ++ { CCI_REG32(0xe170), 0x17d0163 }, ++ { CCI_REG32(0xe174), 0x1c4019a }, ++ { CCI_REG32(0xe178), 0x20d01d6 }, ++ { CCI_REG32(0xe17c), 0x2630224 }, ++ { CCI_REG32(0xe180), 0x257021d }, ++ { CCI_REG32(0xe184), 0x20001d0 }, ++ { CCI_REG32(0xe188), 0x1b90194 }, ++ { CCI_REG32(0xe18c), 0x175015d }, ++ { CCI_REG32(0xe190), 0x13e0132 }, ++ { CCI_REG32(0xe194), 0x1180114 }, ++ { CCI_REG32(0xe198), 0x1040103 }, ++ { CCI_REG32(0xe19c), 0x1000100 }, ++ { CCI_REG32(0xe1a0), 0x1030102 }, ++ { CCI_REG32(0xe1a4), 0x1050103 }, ++ { CCI_REG32(0xe1a8), 0x11d0118 }, ++ { CCI_REG32(0xe1ac), 0x1450136 }, ++ { CCI_REG32(0xe1b0), 0x17d0163 }, ++ { CCI_REG32(0xe1b4), 0x1c4019a }, ++ { CCI_REG32(0xe1b8), 0x20d01d6 }, ++ { CCI_REG32(0xe1bc), 0x2640224 }, ++ { CCI_REG32(0xe1c0), 0x258021f }, ++ { CCI_REG32(0xe1c4), 0x20e01db }, ++ { CCI_REG32(0xe1c8), 0x1c7019f }, ++ { CCI_REG32(0xe1cc), 0x1840169 }, ++ { CCI_REG32(0xe1d0), 0x14d013e }, ++ { CCI_REG32(0xe1d4), 0x1290120 }, ++ { CCI_REG32(0xe1d8), 0x1180114 }, ++ { CCI_REG32(0xe1dc), 0x1050103 }, ++ { CCI_REG32(0xe1e0), 0x1050103 }, ++ { CCI_REG32(0xe1e4), 0x11e0117 }, ++ { CCI_REG32(0xe1e8), 0x12c0123 }, ++ { CCI_REG32(0xe1ec), 0x1530142 }, ++ { CCI_REG32(0xe1f0), 0x18d016f }, ++ { CCI_REG32(0xe1f4), 0x1d201a6 }, ++ { CCI_REG32(0xe1f8), 0x21a01e2 }, ++ { CCI_REG32(0xe1fc), 0x2640225 }, ++ { CCI_REG32(0xe200), 0x269022d }, ++ { CCI_REG32(0xe204), 0x22601f1 }, ++ { CCI_REG32(0xe208), 0x1e101b4 }, ++ { CCI_REG32(0xe20c), 0x1a10181 }, ++ { CCI_REG32(0xe210), 0x16c0156 }, ++ { CCI_REG32(0xe214), 0x14d013e }, ++ { CCI_REG32(0xe218), 0x1290120 }, ++ { CCI_REG32(0xe21c), 0x11f0118 }, ++ { CCI_REG32(0xe220), 0x11f0118 }, ++ { CCI_REG32(0xe224), 0x12b0123 }, ++ { CCI_REG32(0xe228), 0x1530142 }, ++ { CCI_REG32(0xe22c), 0x172015a }, ++ { CCI_REG32(0xe230), 0x1aa0187 }, ++ { CCI_REG32(0xe234), 0x1ec01bb }, ++ { CCI_REG32(0xe238), 0x23301f8 }, ++ { CCI_REG32(0xe23c), 0x2750233 }, ++ { CCI_REG32(0xe240), 0x28b024c }, ++ { CCI_REG32(0xe244), 0x24f0216 }, ++ { CCI_REG32(0xe248), 0x20701d4 }, ++ { CCI_REG32(0xe24c), 0x1ce01a4 }, ++ { CCI_REG32(0xe250), 0x1a10181 }, ++ { CCI_REG32(0xe254), 0x16c0156 }, ++ { CCI_REG32(0xe258), 0x1520141 }, ++ { CCI_REG32(0xe25c), 0x1480138 }, ++ { CCI_REG32(0xe260), 0x1480138 }, ++ { CCI_REG32(0xe264), 0x1550143 }, ++ { CCI_REG32(0xe268), 0x172015a }, ++ { CCI_REG32(0xe26c), 0x1aa0187 }, ++ { CCI_REG32(0xe270), 0x1d701a9 }, ++ { CCI_REG32(0xe274), 0x21201db }, ++ { CCI_REG32(0xe278), 0x25d021d }, ++ { CCI_REG32(0xe27c), 0x2990254 }, ++ { CCI_REG32(0xe280), 0x2d70291 }, ++ { CCI_REG32(0xe284), 0x28c024c }, ++ { CCI_REG32(0xe288), 0x2390201 }, ++ { CCI_REG32(0xe28c), 0x20701d4 }, ++ { CCI_REG32(0xe290), 0x1ce01a4 }, ++ { CCI_REG32(0xe294), 0x1a70184 }, ++ { CCI_REG32(0xe298), 0x18c016e }, ++ { CCI_REG32(0xe29c), 0x1810164 }, ++ { CCI_REG32(0xe2a0), 0x1810164 }, ++ { CCI_REG32(0xe2a4), 0x1900170 }, ++ { CCI_REG32(0xe2a8), 0x1ad0188 }, ++ { CCI_REG32(0xe2ac), 0x1d601a9 }, ++ { CCI_REG32(0xe2b0), 0x21201da }, ++ { CCI_REG32(0xe2b4), 0x2450207 }, ++ { CCI_REG32(0xe2b8), 0x29a0254 }, ++ { CCI_REG32(0xe2bc), 0x2ea029d }, ++ { CCI_REG32(0xe2c0), 0x2f602ae }, ++ { CCI_REG32(0xe2c4), 0x2d80291 }, ++ { CCI_REG32(0xe2c8), 0x280023f }, ++ { CCI_REG32(0xe2cc), 0x2390200 }, ++ { CCI_REG32(0xe2d0), 0x1fe01cc }, ++ { CCI_REG32(0xe2d4), 0x1d201a4 }, ++ { CCI_REG32(0xe2d8), 0x1c6019b }, ++ { CCI_REG32(0xe2dc), 0x1c6019b }, ++ { CCI_REG32(0xe2e0), 0x1c6019b }, ++ { CCI_REG32(0xe2e4), 0x1c8019b }, ++ { CCI_REG32(0xe2e8), 0x1d701a9 }, ++ { CCI_REG32(0xe2ec), 0x20801d1 }, ++ { CCI_REG32(0xe2f0), 0x2450206 }, ++ { CCI_REG32(0xe2f4), 0x28e0248 }, ++ { CCI_REG32(0xe2f8), 0x2ec029d }, ++ { CCI_REG32(0xe2fc), 0x30902b9 }, ++ { CCI_REG32(0xe300), 0x2a002a4 }, ++ { CCI_REG32(0xe304), 0x2830286 }, ++ { CCI_REG32(0xe308), 0x2330234 }, ++ { CCI_REG32(0xe30c), 0x1f601f7 }, ++ { CCI_REG32(0xe310), 0x1c301c4 }, ++ { CCI_REG32(0xe314), 0x19c019c }, ++ { CCI_REG32(0xe318), 0x1920193 }, ++ { CCI_REG32(0xe31c), 0x1920193 }, ++ { CCI_REG32(0xe320), 0x1920192 }, ++ { CCI_REG32(0xe324), 0x1920193 }, ++ { CCI_REG32(0xe328), 0x19f01a1 }, ++ { CCI_REG32(0xe32c), 0x1c801ca }, ++ { CCI_REG32(0xe330), 0x1fb01fe }, ++ { CCI_REG32(0xe334), 0x239023e }, ++ { CCI_REG32(0xe338), 0x28a0292 }, ++ { CCI_REG32(0xe33c), 0x2a802b0 }, ++ { CCI_REG32(0xe340), 0x2830287 }, ++ { CCI_REG32(0xe344), 0x2400242 }, ++ { CCI_REG32(0xe348), 0x1f601f8 }, ++ { CCI_REG32(0xe34c), 0x1cd01ce }, ++ { CCI_REG32(0xe350), 0x19c019d }, ++ { CCI_REG32(0xe354), 0x17b017d }, ++ { CCI_REG32(0xe358), 0x1650166 }, ++ { CCI_REG32(0xe35c), 0x15c015d }, ++ { CCI_REG32(0xe360), 0x15c015d }, ++ { CCI_REG32(0xe364), 0x1670168 }, ++ { CCI_REG32(0xe368), 0x17e0180 }, ++ { CCI_REG32(0xe36c), 0x1a101a3 }, ++ { CCI_REG32(0xe370), 0x1d101d3 }, ++ { CCI_REG32(0xe374), 0x1fc0200 }, ++ { CCI_REG32(0xe378), 0x246024c }, ++ { CCI_REG32(0xe37c), 0x28a0291 }, ++ { CCI_REG32(0xe380), 0x2430245 }, ++ { CCI_REG32(0xe384), 0x20e0211 }, ++ { CCI_REG32(0xe388), 0x1ce01d0 }, ++ { CCI_REG32(0xe38c), 0x19c019e }, ++ { CCI_REG32(0xe390), 0x17b017c }, ++ { CCI_REG32(0xe394), 0x1500152 }, ++ { CCI_REG32(0xe398), 0x13a013c }, ++ { CCI_REG32(0xe39c), 0x1310134 }, ++ { CCI_REG32(0xe3a0), 0x1310134 }, ++ { CCI_REG32(0xe3a4), 0x13c013f }, ++ { CCI_REG32(0xe3a8), 0x1540156 }, ++ { CCI_REG32(0xe3ac), 0x17e0180 }, ++ { CCI_REG32(0xe3b0), 0x1a101a4 }, ++ { CCI_REG32(0xe3b4), 0x1d301d8 }, ++ { CCI_REG32(0xe3b8), 0x2140219 }, ++ { CCI_REG32(0xe3bc), 0x249024e }, ++ { CCI_REG32(0xe3c0), 0x229022b }, ++ { CCI_REG32(0xe3c4), 0x1ed01ef }, ++ { CCI_REG32(0xe3c8), 0x1b001b2 }, ++ { CCI_REG32(0xe3cc), 0x17c017e }, ++ { CCI_REG32(0xe3d0), 0x1500151 }, ++ { CCI_REG32(0xe3d4), 0x13a013c }, ++ { CCI_REG32(0xe3d8), 0x11c011f }, ++ { CCI_REG32(0xe3dc), 0x1130117 }, ++ { CCI_REG32(0xe3e0), 0x1130117 }, ++ { CCI_REG32(0xe3e4), 0x1200123 }, ++ { CCI_REG32(0xe3e8), 0x13c013f }, ++ { CCI_REG32(0xe3ec), 0x1540156 }, ++ { CCI_REG32(0xe3f0), 0x1810183 }, ++ { CCI_REG32(0xe3f4), 0x1b601ba }, ++ { CCI_REG32(0xe3f8), 0x1f301f6 }, ++ { CCI_REG32(0xe3fc), 0x2300234 }, ++ { CCI_REG32(0xe400), 0x21d0221 }, ++ { CCI_REG32(0xe404), 0x1d801db }, ++ { CCI_REG32(0xe408), 0x19d019f }, ++ { CCI_REG32(0xe40c), 0x1670169 }, ++ { CCI_REG32(0xe410), 0x13b013d }, ++ { CCI_REG32(0xe414), 0x11c011f }, ++ { CCI_REG32(0xe418), 0x1130117 }, ++ { CCI_REG32(0xe41c), 0x1010106 }, ++ { CCI_REG32(0xe420), 0x1020108 }, ++ { CCI_REG32(0xe424), 0x1130117 }, ++ { CCI_REG32(0xe428), 0x1200123 }, ++ { CCI_REG32(0xe42c), 0x13f0142 }, ++ { CCI_REG32(0xe430), 0x16c016f }, ++ { CCI_REG32(0xe434), 0x1a301a6 }, ++ { CCI_REG32(0xe438), 0x1df01e2 }, ++ { CCI_REG32(0xe43c), 0x2240228 }, ++ { CCI_REG32(0xe440), 0x21d0220 }, ++ { CCI_REG32(0xe444), 0x1d001d3 }, ++ { CCI_REG32(0xe448), 0x1940196 }, ++ { CCI_REG32(0xe44c), 0x15d0160 }, ++ { CCI_REG32(0xe450), 0x1320135 }, ++ { CCI_REG32(0xe454), 0x1140118 }, ++ { CCI_REG32(0xe458), 0x1010106 }, ++ { CCI_REG32(0xe45c), 0x1000106 }, ++ { CCI_REG32(0xe460), 0x1000106 }, ++ { CCI_REG32(0xe464), 0x1030109 }, ++ { CCI_REG32(0xe468), 0x118011b }, ++ { CCI_REG32(0xe46c), 0x136013a }, ++ { CCI_REG32(0xe470), 0x1630165 }, ++ { CCI_REG32(0xe474), 0x19a019c }, ++ { CCI_REG32(0xe478), 0x1d601d9 }, ++ { CCI_REG32(0xe47c), 0x2240227 }, ++ { CCI_REG32(0xe480), 0x21d0220 }, ++ { CCI_REG32(0xe484), 0x1d001d3 }, ++ { CCI_REG32(0xe488), 0x1940196 }, ++ { CCI_REG32(0xe48c), 0x15d0160 }, ++ { CCI_REG32(0xe490), 0x1320135 }, ++ { CCI_REG32(0xe494), 0x1140118 }, ++ { CCI_REG32(0xe498), 0x1030109 }, ++ { CCI_REG32(0xe49c), 0x1000106 }, ++ { CCI_REG32(0xe4a0), 0x1020108 }, ++ { CCI_REG32(0xe4a4), 0x1030109 }, ++ { CCI_REG32(0xe4a8), 0x118011b }, ++ { CCI_REG32(0xe4ac), 0x1360139 }, ++ { CCI_REG32(0xe4b0), 0x1630165 }, ++ { CCI_REG32(0xe4b4), 0x19a019c }, ++ { CCI_REG32(0xe4b8), 0x1d601d9 }, ++ { CCI_REG32(0xe4bc), 0x2240227 }, ++ { CCI_REG32(0xe4c0), 0x21f0221 }, ++ { CCI_REG32(0xe4c4), 0x1db01de }, ++ { CCI_REG32(0xe4c8), 0x19f01a2 }, ++ { CCI_REG32(0xe4cc), 0x169016c }, ++ { CCI_REG32(0xe4d0), 0x13e0141 }, ++ { CCI_REG32(0xe4d4), 0x1200124 }, ++ { CCI_REG32(0xe4d8), 0x1140119 }, ++ { CCI_REG32(0xe4dc), 0x1030109 }, ++ { CCI_REG32(0xe4e0), 0x1030109 }, ++ { CCI_REG32(0xe4e4), 0x117011c }, ++ { CCI_REG32(0xe4e8), 0x1230126 }, ++ { CCI_REG32(0xe4ec), 0x1420145 }, ++ { CCI_REG32(0xe4f0), 0x16f0171 }, ++ { CCI_REG32(0xe4f4), 0x1a601a8 }, ++ { CCI_REG32(0xe4f8), 0x1e201e4 }, ++ { CCI_REG32(0xe4fc), 0x2250227 }, ++ { CCI_REG32(0xe500), 0x22d0231 }, ++ { CCI_REG32(0xe504), 0x1f101f4 }, ++ { CCI_REG32(0xe508), 0x1b401b7 }, ++ { CCI_REG32(0xe50c), 0x1810183 }, ++ { CCI_REG32(0xe510), 0x1560159 }, ++ { CCI_REG32(0xe514), 0x13e0141 }, ++ { CCI_REG32(0xe518), 0x1200124 }, ++ { CCI_REG32(0xe51c), 0x118011c }, ++ { CCI_REG32(0xe520), 0x118011c }, ++ { CCI_REG32(0xe524), 0x1230126 }, ++ { CCI_REG32(0xe528), 0x1420145 }, ++ { CCI_REG32(0xe52c), 0x15a015c }, ++ { CCI_REG32(0xe530), 0x1870188 }, ++ { CCI_REG32(0xe534), 0x1bb01bd }, ++ { CCI_REG32(0xe538), 0x1f801fb }, ++ { CCI_REG32(0xe53c), 0x2330236 }, ++ { CCI_REG32(0xe540), 0x24c0250 }, ++ { CCI_REG32(0xe544), 0x2160219 }, ++ { CCI_REG32(0xe548), 0x1d401d7 }, ++ { CCI_REG32(0xe54c), 0x1a401a6 }, ++ { CCI_REG32(0xe550), 0x1810183 }, ++ { CCI_REG32(0xe554), 0x1560158 }, ++ { CCI_REG32(0xe558), 0x1410144 }, ++ { CCI_REG32(0xe55c), 0x138013b }, ++ { CCI_REG32(0xe560), 0x138013b }, ++ { CCI_REG32(0xe564), 0x1430146 }, ++ { CCI_REG32(0xe568), 0x15a015c }, ++ { CCI_REG32(0xe56c), 0x1870188 }, ++ { CCI_REG32(0xe570), 0x1a901ab }, ++ { CCI_REG32(0xe574), 0x1db01dd }, ++ { CCI_REG32(0xe578), 0x21d0221 }, ++ { CCI_REG32(0xe57c), 0x2540259 }, ++ { CCI_REG32(0xe580), 0x2910296 }, ++ { CCI_REG32(0xe584), 0x24c0251 }, ++ { CCI_REG32(0xe588), 0x2010204 }, ++ { CCI_REG32(0xe58c), 0x1d401d6 }, ++ { CCI_REG32(0xe590), 0x1a401a5 }, ++ { CCI_REG32(0xe594), 0x1840186 }, ++ { CCI_REG32(0xe598), 0x16e0170 }, ++ { CCI_REG32(0xe59c), 0x1640167 }, ++ { CCI_REG32(0xe5a0), 0x1640167 }, ++ { CCI_REG32(0xe5a4), 0x1700173 }, ++ { CCI_REG32(0xe5a8), 0x188018a }, ++ { CCI_REG32(0xe5ac), 0x1a901ab }, ++ { CCI_REG32(0xe5b0), 0x1da01dd }, ++ { CCI_REG32(0xe5b4), 0x207020a }, ++ { CCI_REG32(0xe5b8), 0x2540259 }, ++ { CCI_REG32(0xe5bc), 0x29d02a3 }, ++ { CCI_REG32(0xe5c0), 0x2ae02b4 }, ++ { CCI_REG32(0xe5c4), 0x2910297 }, ++ { CCI_REG32(0xe5c8), 0x23f0243 }, ++ { CCI_REG32(0xe5cc), 0x2000201 }, ++ { CCI_REG32(0xe5d0), 0x1cc01cd }, ++ { CCI_REG32(0xe5d4), 0x1a401a6 }, ++ { CCI_REG32(0xe5d8), 0x19b019d }, ++ { CCI_REG32(0xe5dc), 0x19b019d }, ++ { CCI_REG32(0xe5e0), 0x19b019d }, ++ { CCI_REG32(0xe5e4), 0x19b019e }, ++ { CCI_REG32(0xe5e8), 0x1a901ab }, ++ { CCI_REG32(0xe5ec), 0x1d101d3 }, ++ { CCI_REG32(0xe5f0), 0x2060209 }, ++ { CCI_REG32(0xe5f4), 0x248024b }, ++ { CCI_REG32(0xe5f8), 0x29d02a3 }, ++ { CCI_REG32(0xe5fc), 0x2b902c0 }, ++ { CCI_REG8(0xd822), 0x01 }, ++ { CCI_REG8(0xd823), 0x0f }, ++}; ++ ++/* Mode configs */ ++static const struct imx500_mode imx500_supported_modes[] = { ++ { ++ /* 12MPix 10fps mode */ ++ .width = 4056, ++ .height = 3040, ++ .line_length_pix = 17900, ++ .crop = { ++ .left = IMX500_PIXEL_ARRAY_LEFT, ++ .top = IMX500_PIXEL_ARRAY_TOP, ++ .width = 4056, ++ .height = 3040, ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), ++ .regs = mode_4056x3040_regs, ++ }, ++ }, ++ { ++ /* 2x2 binned 40fps mode */ ++ .width = 2028, ++ .height = 1520, ++ .line_length_pix = 9398, ++ .crop = { ++ .left = IMX500_PIXEL_ARRAY_LEFT, ++ .top = IMX500_PIXEL_ARRAY_TOP, ++ .width = 4056, ++ .height = 3040, ++ }, ++ .reg_list = { ++ .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs), ++ .regs = mode_2028x1520_regs, ++ }, ++ }, ++}; ++ ++/* ++ * The supported formats. ++ * This table MUST contain 4 entries per format, to cover the various flip ++ * combinations in the order ++ * - no flip ++ * - h flip ++ * - v flip ++ * - h&v flips ++ */ ++static const u32 codes[] = { ++ /* 10-bit modes. */ ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++}; ++ ++enum imx500_state { ++ IMX500_STATE_RESET = 0, ++ IMX500_STATE_PROGRAM_EMPTY, ++ IMX500_STATE_WITHOUT_NETWORK, ++ IMX500_STATE_WITH_NETWORK, ++}; ++ ++struct imx500 { ++ struct dentry *debugfs; ++ struct v4l2_subdev sd; ++ struct media_pad pad[NUM_PADS]; ++ struct regmap *regmap; ++ ++ unsigned int fmt_code; ++ ++ struct clk *xclk; ++ u32 xclk_freq; ++ ++ struct gpio_desc *led_gpio; ++ struct gpio_desc *reset_gpio; ++ struct regulator_bulk_data supplies[IMX500_NUM_SUPPLIES]; ++ ++ struct v4l2_ctrl_handler ctrl_handler; ++ /* V4L2 Controls */ ++ struct v4l2_ctrl *pixel_rate; ++ struct v4l2_ctrl *link_freq; ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; ++ struct v4l2_ctrl *network_fw_ctrl; ++ ++ struct v4l2_rect inference_window; ++ ++ /* Current mode */ ++ const struct imx500_mode *mode; ++ ++ /* ++ * Mutex for serialized access: ++ * Protect sensor module set pad format and start/stop streaming safely. ++ */ ++ struct mutex mutex; ++ ++ /* Streaming on/off */ ++ bool streaming; ++ ++ /* Rewrite common registers on stream on? */ ++ bool common_regs_written; ++ ++ bool loader_and_main_written; ++ bool network_written; ++ ++ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */ ++ unsigned int long_exp_shift; ++ ++ struct spi_device *spi_device; ++ ++ const struct firmware *fw_loader; ++ const struct firmware *fw_main; ++ const u8 *fw_network; ++ size_t fw_network_size; ++ size_t fw_progress; ++ unsigned int fw_stage; ++ ++ enum imx500_state fsm_state; ++ ++ u32 num_inference_lines; ++}; ++ ++static inline struct imx500 *to_imx500(struct v4l2_subdev *_sd) ++{ ++ return container_of(_sd, struct imx500, sd); ++} ++ ++static bool validate_normalization_yuv(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ /* Some regs are 9-bit, some 8-bit, some 1-bit */ ++ switch (reg) { ++ case 0xD62A: ++ case 0xD632: ++ case 0xD63A: ++ case 0xD644: ++ case 0xD648: ++ case 0xD64C: ++ case 0xD650: ++ case 0xD654: ++ case 0xD658: ++ return size == 2 && !(value & ~0x1FF); ++ case 0xD600: ++ case 0xD601: ++ case 0xD602: ++ return size == 1 && !(value & ~0xFF); ++ case 0xD629: ++ case 0xD630: ++ case 0xD638: ++ case 0xD643: ++ case 0xD647: ++ case 0xD64B: ++ case 0xD64F: ++ case 0xD653: ++ case 0xD657: ++ return size == 1 && !(value & ~0x01); ++ default: ++ return false; ++ } ++} ++ ++/* Common function as bayer rgb + normalization use the same repeating register ++ * layout ++ */ ++static bool validate_bit_pattern(u8 offset, uint8_t size, uint32_t value) ++{ ++ /* There are no odd register addresses */ ++ if (offset & 1) ++ return false; ++ ++ /* Valid register sizes/patterns repeat every 4 */ ++ offset = (offset >> 1) & 3; ++ ++ if (offset == 1) ++ return size == 1 && !(value & ~1); ++ else ++ return size == 2 && !(value & ~0x1FF); ++} ++ ++static bool validate_bayer_rgb_normalization(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (reg < 0xD684 || reg >= 0xD6E4) ++ return false; ++ return validate_bit_pattern(reg - 0xD684, size, value); ++} ++ ++static bool validate_normalization_registers(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (reg < 0xD708 || reg >= 0xD750) ++ return false; ++ return validate_bit_pattern(reg - 0xD708, size, value); ++} ++ ++static bool validate_image_format_selection(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ if (size != 1 || value > 5) ++ return false; ++ if (reg < 0xD750 || reg > 0xd752) ++ return false; ++ return true; ++} ++ ++static bool validate_yc_conversion_factor(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ static const u32 allowed[9] = { ++ 0x0FFF0FFF, 0x0FFF1FFF, 0x0FFF0FFF, 0x0FFF1FFF, 0x0FFF0FFF, ++ 0x0FFF1FFF, 0x01FF01FF, 0x01FF01FF, 0x01FF01FF, ++ }; ++ ++ if (size > 4 || size & 1 || reg & 1 || reg < 0x76C || reg > 0xD7FA) ++ return false; ++ ++ if (size == 2) { ++ if (reg & 2) ++ reg -= 2; ++ else ++ value <<= 16; ++ } ++ ++ /* High registers (clip values) are all 2x 9-bit */ ++ if (reg >= 0xD7D8) ++ return !(value & ~0x01FF01FF); ++ ++ /* Early registers follow a repeating pattern */ ++ reg -= 0xD76C; ++ reg >>= 2; ++ return !(value & ~allowed[reg % sizeof(allowed)]); ++} ++ ++static bool validate_dnn_output_setting(u16 reg, uint8_t size, ++ uint32_t value) ++{ ++ /* Only Y_OUT_SIZE for Input Tensor / Output Tensor is configurable from ++ * userspace ++ */ ++ return (size == 2) && (value < 2046) && ++ ((reg == CCI_REG_ADDR(IMX500_REG_DD_CH07_Y_OUT_SIZE)) || ++ (reg == CCI_REG_ADDR(IMX500_REG_DD_CH08_Y_OUT_SIZE))); ++} ++ ++static bool __must_check ++imx500_validate_inference_register(const struct cci_reg_sequence *reg) ++{ ++ unsigned int i; ++ ++ static bool (*const checks[])(uint16_t, uint8_t, uint32_t) = { ++ validate_normalization_yuv, ++ validate_bayer_rgb_normalization, ++ validate_normalization_registers, ++ validate_image_format_selection, ++ validate_yc_conversion_factor, ++ validate_dnn_output_setting, ++ }; ++ ++ if (!reg) ++ return false; ++ ++ for (i = 0; i < ARRAY_SIZE(checks); i++) { ++ if (checks[i](CCI_REG_ADDR(reg->reg), ++ CCI_REG_WIDTH_BYTES(reg->reg), reg->val)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int imx500_set_inference_window(struct imx500 *imx500) ++{ ++ u16 left, top, width, height; ++ ++ if (!imx500->inference_window.width || ++ !imx500->inference_window.height) { ++ width = 4056; ++ height = 3040; ++ left = 0; ++ top = 0; ++ } else { ++ width = min_t(u16, imx500->inference_window.width, 4056); ++ height = min_t(u16, imx500->inference_window.height, 3040); ++ left = min_t(u16, imx500->inference_window.left, 4056); ++ top = min_t(u16, imx500->inference_window.top, 3040); ++ } ++ ++ const struct cci_reg_sequence window_regs[] = { ++ { IMX500_REG_DWP_AP_VC_HOFF, left }, ++ { IMX500_REG_DWP_AP_VC_VOFF, top }, ++ { IMX500_REG_DWP_AP_VC_HSIZE, width }, ++ { IMX500_REG_DWP_AP_VC_VSIZE, height }, ++ }; ++ ++ return cci_multi_reg_write(imx500->regmap, window_regs, ++ ARRAY_SIZE(window_regs), NULL); ++} ++ ++static int imx500_reg_val_write_cbk(void *arg, ++ const struct cci_reg_sequence *reg) ++{ ++ struct imx500 *imx500 = arg; ++ ++ if (!imx500_validate_inference_register(reg)) ++ return -EINVAL; ++ ++ return cci_write(imx500->regmap, reg->reg, reg->val, NULL); ++} ++ ++/* Get bayer order based on flip setting. */ ++static u32 imx500_get_format_code(struct imx500 *imx500) ++{ ++ unsigned int i; ++ ++ lockdep_assert_held(&imx500->mutex); ++ ++ i = (imx500->vflip->val ? 2 : 0) | (imx500->hflip->val ? 1 : 0); ++ ++ return codes[i]; ++} ++ ++static void imx500_set_default_format(struct imx500 *imx500) ++{ ++ /* Set default mode to max resolution */ ++ imx500->mode = &imx500_supported_modes[0]; ++ imx500->fmt_code = MEDIA_BUS_FMT_SRGGB10_1X10; ++} ++ ++/* -1 on fail, block size on success */ ++static int imx500_validate_fw_block(const char *data, size_t maxlen) ++{ ++ const size_t header_size = 32; ++ static const char header_id[] = { '9', '4', '6', '4' }; ++ ++ const size_t footer_size = 64; ++ static const char footer_id[] = { '3', '6', '9', '5' }; ++ ++ u32 data_size; ++ ++ const char *end = data + maxlen; ++ ++ if (!data) ++ return -1; ++ ++ if (maxlen < header_size) ++ return -1; ++ ++ if (memcmp(data, &header_id, sizeof(header_id))) ++ return -1; ++ ++ /* data_size is size of header + body */ ++ memcpy(&data_size, data + sizeof(header_id), sizeof(data_size)); ++ data_size = ___constant_swab32(data_size); ++ ++ if (end - data_size - footer_size < data) ++ return -1; ++ if (memcmp(data + data_size + footer_size - sizeof(footer_id), ++ &footer_id, sizeof(footer_id))) ++ return -1; ++ ++ return data_size + footer_size; ++} ++ ++/* Parse fw block by block, returning total valid fw size */ ++static size_t imx500_valid_fw_bytes(const u8 *fw, ++ const size_t fw_size) ++{ ++ int i; ++ size_t bytes = 0; ++ ++ const u8 *data = fw; ++ size_t size = fw_size; ++ ++ while ((i = imx500_validate_fw_block(data, size)) > 0) { ++ bytes += i; ++ data += i; ++ size -= i; ++ } ++ ++ return bytes; ++} ++ ++static int imx500_iterate_nw_regs( ++ const u8 *fw, size_t fw_size, void *arg, ++ int (*cbk)(void *arg, const struct cci_reg_sequence *reg)) ++{ ++ struct cpio_data cd = { NULL, 0, "" }; ++ const u8 *read_pos; ++ size_t entries; ++ size_t size; ++ ++ if (!fw || !cbk) ++ return -EINVAL; ++ ++ size = imx500_valid_fw_bytes(fw, fw_size); ++ cd = find_cpio_data("imx500_regs", (void *)(fw + size), ++ fw_size - size, NULL); ++ if (!cd.data || cd.size % 7) ++ return -EINVAL; ++ ++ read_pos = cd.data; ++ entries = cd.size / 7; ++ ++ while (entries--) { ++ struct cci_reg_sequence reg = { 0, 0 }; ++ u16 addr; ++ u8 len; ++ u32 val; ++ int ret; ++ ++ memcpy(&addr, read_pos, sizeof(addr)); ++ read_pos += sizeof(addr); ++ memcpy(&len, read_pos, sizeof(len)); ++ read_pos += sizeof(len); ++ memcpy(&val, read_pos, sizeof(val)); ++ read_pos += sizeof(val); ++ ++ reg.reg = ((len << CCI_REG_WIDTH_SHIFT) | addr); ++ reg.val = val; ++ ++ ret = cbk(arg, ®); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static int imx500_reg_tensor_lines_cbk(void *arg, ++ const struct cci_reg_sequence *reg) ++{ ++ u16 *tensor_lines = arg; ++ ++ if (reg->val < 2046) { ++ switch (reg->reg) { ++ case IMX500_REG_DD_CH07_Y_OUT_SIZE: ++ tensor_lines[0] = reg->val; ++ break; ++ case IMX500_REG_DD_CH08_Y_OUT_SIZE: ++ tensor_lines[1] = reg->val; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static void imx500_calc_inference_lines(struct imx500 *imx500) ++{ ++ u16 tensor_lines[2] = { 0, 0 }; ++ ++ if (!imx500->fw_network) { ++ imx500->num_inference_lines = 0; ++ return; ++ } ++ ++ imx500_iterate_nw_regs(imx500->fw_network, imx500->fw_network_size, ++ tensor_lines, imx500_reg_tensor_lines_cbk); ++ ++ /* Full-res mode, embedded lines are actually slightly shorter than inference ++ * lines 2544 vs 2560 (over-allocate with inf. width) ++ */ ++ imx500->num_inference_lines = IMX500_NUM_KPI_LINES + ++ IMX500_NUM_PQ_LINES + tensor_lines[0] + ++ tensor_lines[1]; ++} ++ ++static void imx500_adjust_exposure_range(struct imx500 *imx500) ++{ ++ int exposure_max, exposure_def; ++ ++ /* Honour the VBLANK limits when setting exposure. */ ++ exposure_max = imx500->mode->height + imx500->vblank->val - ++ IMX500_EXPOSURE_OFFSET; ++ exposure_def = min(exposure_max, imx500->exposure->val); ++ __v4l2_ctrl_modify_range(imx500->exposure, imx500->exposure->minimum, ++ exposure_max, imx500->exposure->step, ++ exposure_def); ++} ++ ++static int imx500_set_frame_length(struct imx500 *imx500, unsigned int val) ++{ ++ int ret = 0; ++ ++ imx500->long_exp_shift = 0; ++ ++ while (val > IMX500_FRAME_LENGTH_MAX) { ++ imx500->long_exp_shift++; ++ val >>= 1; ++ } ++ ++ ret = cci_write(imx500->regmap, IMX500_REG_FRAME_LENGTH, val, NULL); ++ if (ret) ++ return ret; ++ ++ return cci_write(imx500->regmap, IMX500_LONG_EXP_SHIFT_REG, ++ imx500->long_exp_shift, NULL); ++} ++ ++/* reg is both input and output: ++ * reg->val is the value we're polling until we're NEQ to ++ * It is then populated with the updated value. ++ */ ++static int __must_check imx500_poll_status_reg(struct imx500 *state, ++ struct cci_reg_sequence *reg, ++ u8 timeout) ++{ ++ u64 read_value; ++ int ret; ++ ++ while (timeout) { ++ ret = cci_read(state->regmap, reg->reg, &read_value, NULL); ++ if (ret) ++ return ret; ++ ++ if (read_value != reg->val) { ++ reg->val = read_value; ++ return 0; ++ } ++ ++ timeout--; ++ mdelay(50); ++ } ++ return -EAGAIN; ++} ++ ++static int imx500_prepare_poll_cmd_reply_sts(struct imx500 *imx500, ++ struct cci_reg_sequence *cmd_reply) ++{ ++ /* Perform single-byte read of 4-byte IMX500_REG_DD_REF_STS register to ++ * target CMD_REPLY_STS_CNT sub-register ++ */ ++ cmd_reply->reg = CCI_REG8(CCI_REG_ADDR(IMX500_REG_DD_REF_STS)); ++ ++ return cci_read(imx500->regmap, cmd_reply->reg, &cmd_reply->val, NULL); ++} ++ ++static int imx500_clear_weights(struct imx500 *imx500) ++{ ++ struct cci_reg_sequence cmd_reply_sts_cnt_reg; ++ u64 imx500_fsm_state; ++ u64 cmd_reply; ++ int ret; ++ ++ static const struct cci_reg_sequence request_clear[] = { ++ { IMX500_REG_DD_ST_TRANS_CMD, ++ IMX500_DD_ST_TRANS_CMD_CLEAR_WEIGHTS }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_ST_TRANS }, ++ }; ++ ++ if (imx500->fsm_state != IMX500_STATE_WITH_NETWORK) ++ return -EINVAL; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_SYS_STATE, ++ &imx500_fsm_state, NULL); ++ if (ret || imx500_fsm_state != IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK) ++ return ret ? ret : -EREMOTEIO; ++ ++ ret = imx500_prepare_poll_cmd_reply_sts(imx500, &cmd_reply_sts_cnt_reg); ++ if (ret) ++ return ret; ++ ++ ret = cci_multi_reg_write(imx500->regmap, request_clear, ++ ARRAY_SIZE(request_clear), NULL); ++ if (ret) ++ return ret; ++ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) ++ return ret; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &cmd_reply, ++ NULL); ++ if (ret || cmd_reply != IMX500_DD_CMD_REPLY_STS_TRANS_DONE) ++ return ret ? ret : -EREMOTEIO; ++ ++ imx500->fsm_state = IMX500_STATE_WITHOUT_NETWORK; ++ imx500->network_written = false; ++ return 0; ++} ++ ++static void imx500_clear_fw_network(struct imx500 *imx500) ++{ ++ /* Remove any previous firmware blob. */ ++ if (imx500->fw_network) ++ vfree(imx500->fw_network); ++ ++ imx500->fw_network = NULL; ++ imx500->network_written = false; ++ imx500->fw_progress = 0; ++} ++ ++static int imx500_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct imx500 *imx500 = ++ container_of(ctrl->handler, struct imx500, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret = 0; ++ ++ if (ctrl->id == V4L2_CID_USER_IMX500_NETWORK_FW_FD) { ++ /* Reset state of the control. */ ++ if (ctrl->val < 0) { ++ return 0; ++ } else if (ctrl->val == S32_MAX) { ++ ctrl->val = -1; ++ if (pm_runtime_get_if_in_use(&client->dev) == 0) ++ return 0; ++ ++ if (imx500->network_written) ++ ret = imx500_clear_weights(imx500); ++ imx500_clear_fw_network(imx500); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++ } ++ ++ imx500_clear_fw_network(imx500); ++ ret = kernel_read_file_from_fd(ctrl->val, 0, ++ (void **)&imx500->fw_network, INT_MAX, ++ &imx500->fw_network_size, ++ 1); ++ /* ++ * Back to reset state, the FD cannot be considered valid after ++ * this IOCTL completes. ++ */ ++ ctrl->val = -1; ++ ++ if (ret < 0) { ++ dev_err(&client->dev, "%s failed to read fw image: %d\n", ++ __func__, ret); ++ imx500_clear_fw_network(imx500); ++ return ret; ++ } ++ if (ret != imx500->fw_network_size) { ++ dev_err(&client->dev, "%s read fw image size mismatich: got %u, expected %zu\n", ++ __func__, ret, imx500->fw_network_size); ++ imx500_clear_fw_network(imx500); ++ return -EIO; ++ } ++ ++ imx500_calc_inference_lines(imx500); ++ return 0; ++ } ++ ++ /* ++ * The VBLANK control may change the limits of usable exposure, so check ++ * and adjust if necessary. ++ */ ++ if (ctrl->id == V4L2_CID_VBLANK) ++ imx500_adjust_exposure_range(imx500); ++ ++ /* ++ * Applying V4L2 control value only happens ++ * when power is up for streaming ++ */ ++ if (pm_runtime_get_if_in_use(&client->dev) == 0) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ANALOGUE_GAIN: ++ ret = cci_write(imx500->regmap, IMX500_REG_ANALOG_GAIN, ++ ctrl->val, NULL); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = cci_write(imx500->regmap, IMX500_REG_EXPOSURE, ++ ctrl->val >> imx500->long_exp_shift, NULL); ++ break; ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ ret = cci_write(imx500->regmap, IMX500_REG_ORIENTATION, ++ imx500->hflip->val | imx500->vflip->val << 1, ++ NULL); ++ break; ++ case V4L2_CID_VBLANK: ++ ret = imx500_set_frame_length(imx500, ++ imx500->mode->height + ctrl->val); ++ break; ++ case V4L2_CID_HBLANK: ++ ret = cci_write(imx500->regmap, IMX500_REG_LINE_LENGTH, ++ imx500->mode->width + ctrl->val, NULL); ++ break; ++ case V4L2_CID_NOTIFY_GAINS: ++ ret = cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_B, ++ ctrl->p_new.p_u32[0], NULL); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_GB, ++ ctrl->p_new.p_u32[1], &ret); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_GR, ++ ctrl->p_new.p_u32[2], &ret); ++ cci_write(imx500->regmap, IMX500_REG_COLOUR_BALANCE_R, ++ ctrl->p_new.p_u32[3], &ret); ++ break; ++ case V4L2_CID_USER_IMX500_INFERENCE_WINDOW: ++ memcpy(&imx500->inference_window, ctrl->p_new.p_u32, ++ sizeof(struct v4l2_rect)); ++ ret = imx500_set_inference_window(imx500); ++ break; ++ default: ++ dev_info(&client->dev, ++ "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ++ ctrl->val); ++ ret = -EINVAL; ++ break; ++ } ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops imx500_ctrl_ops = { ++ .s_ctrl = imx500_set_ctrl, ++}; ++ ++static const struct v4l2_ctrl_config imx500_notify_gains_ctrl = { ++ .ops = &imx500_ctrl_ops, ++ .id = V4L2_CID_NOTIFY_GAINS, ++ .type = V4L2_CTRL_TYPE_U32, ++ .min = IMX500_COLOUR_BALANCE_MIN, ++ .max = IMX500_COLOUR_BALANCE_MAX, ++ .step = IMX500_COLOUR_BALANCE_STEP, ++ .def = IMX500_COLOUR_BALANCE_DEFAULT, ++ .dims = { 4 }, ++ .elem_size = sizeof(u32), ++}; ++ ++static int imx500_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (code->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (code->pad == IMAGE_PAD) { ++ if (code->index != 0) ++ return -EINVAL; ++ ++ code->code = imx500_get_format_code(imx500); ++ } else { ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } ++ ++ return 0; ++} ++ ++static int imx500_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fse->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ if (fse->pad == IMAGE_PAD) { ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ ++ if (fse->index >= num_modes) ++ return -EINVAL; ++ ++ if (fse->code != imx500_get_format_code(imx500)) ++ return -EINVAL; ++ ++ fse->min_width = mode_list[fse->index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = mode_list[fse->index].height; ++ fse->max_height = fse->min_height; ++ } else { ++ if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0) ++ return -EINVAL; ++ ++ fse->min_width = IMX500_MAX_EMBEDDED_SIZE + ++ imx500->num_inference_lines * ++ IMX500_INFERENCE_LINE_WIDTH; ++ fse->max_width = fse->min_width; ++ fse->min_height = 1; ++ fse->max_height = fse->min_height; ++ } ++ ++ return 0; ++} ++ ++static void imx500_update_image_pad_format(struct imx500 *imx500, ++ const struct imx500_mode *mode, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = mode->width; ++ fmt->format.height = mode->height; ++ fmt->format.field = V4L2_FIELD_NONE; ++ fmt->format.colorspace = V4L2_COLORSPACE_RAW; ++ fmt->format.ycbcr_enc = ++ V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); ++ fmt->format.quantization = V4L2_MAP_QUANTIZATION_DEFAULT( ++ true, fmt->format.colorspace, fmt->format.ycbcr_enc); ++ fmt->format.xfer_func = ++ V4L2_MAP_XFER_FUNC_DEFAULT(fmt->format.colorspace); ++} ++ ++static void imx500_update_metadata_pad_format(const struct imx500 *imx500, ++ struct v4l2_subdev_format *fmt) ++{ ++ fmt->format.width = ++ IMX500_MAX_EMBEDDED_SIZE + ++ imx500->num_inference_lines * IMX500_INFERENCE_LINE_WIDTH; ++ fmt->format.height = 1; ++ fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format.field = V4L2_FIELD_NONE; ++} ++ ++static int imx500_get_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx500->mutex); ++ ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format( ++ &imx500->sd, sd_state, fmt->pad); ++ /* update the code which could change due to vflip or hflip */ ++ try_fmt->code = fmt->pad == IMAGE_PAD ? ++ imx500_get_format_code(imx500) : ++ MEDIA_BUS_FMT_SENSOR_DATA; ++ fmt->format = *try_fmt; ++ } else { ++ if (fmt->pad == IMAGE_PAD) { ++ imx500_update_image_pad_format(imx500, imx500->mode, ++ fmt); ++ fmt->format.code = imx500_get_format_code(imx500); ++ } else { ++ imx500_update_metadata_pad_format(imx500, fmt); ++ } ++ } ++ ++ mutex_unlock(&imx500->mutex); ++ return 0; ++} ++ ++static void imx500_set_framing_limits(struct imx500 *imx500) ++{ ++ unsigned int hblank_min; ++ const struct imx500_mode *mode = imx500->mode; ++ ++ /* Default to no long exposure multiplier. */ ++ imx500->long_exp_shift = 0; ++ ++ /* Update limits and set FPS to default */ ++ __v4l2_ctrl_modify_range( ++ imx500->vblank, IMX500_VBLANK_MIN, ++ ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) - ++ mode->height, 1, IMX500_VBLANK_MIN); ++ ++ /* Setting this will adjust the exposure limits as well. */ ++ __v4l2_ctrl_s_ctrl(imx500->vblank, IMX500_VBLANK_MIN); ++ ++ hblank_min = mode->line_length_pix - mode->width; ++ __v4l2_ctrl_modify_range(imx500->hblank, hblank_min, hblank_min, 1, ++ hblank_min); ++ __v4l2_ctrl_s_ctrl(imx500->hblank, hblank_min); ++} ++ ++static int imx500_set_pad_format(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct v4l2_mbus_framefmt *framefmt; ++ const struct imx500_mode *mode; ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (fmt->pad >= NUM_PADS) ++ return -EINVAL; ++ ++ mutex_lock(&imx500->mutex); ++ ++ if (fmt->pad == IMAGE_PAD) { ++ const struct imx500_mode *mode_list = imx500_supported_modes; ++ unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes); ++ ++ /* Bayer order varies with flips */ ++ fmt->format.code = imx500_get_format_code(imx500); ++ ++ mode = v4l2_find_nearest_size(mode_list, num_modes, width, ++ height, fmt->format.width, ++ fmt->format.height); ++ imx500_update_image_pad_format(imx500, mode, fmt); ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else if (imx500->mode != mode) { ++ imx500->mode = mode; ++ imx500->fmt_code = fmt->format.code; ++ imx500_set_framing_limits(imx500); ++ } ++ } else { ++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, sd_state, ++ fmt->pad); ++ *framefmt = fmt->format; ++ } else { ++ /* Only one embedded data mode is supported */ ++ imx500_update_metadata_pad_format(imx500, fmt); ++ } ++ } ++ ++ mutex_unlock(&imx500->mutex); ++ ++ return 0; ++} ++ ++static const struct v4l2_rect * ++__imx500_get_pad_crop(struct imx500 *imx500, struct v4l2_subdev_state *sd_state, ++ unsigned int pad, enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(&imx500->sd, sd_state, pad); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &imx500->mode->crop; ++ } ++ ++ return NULL; ++} ++ ++static int imx500_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_state *sd_state, ++ struct v4l2_subdev_selection *sel) ++{ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP: { ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ mutex_lock(&imx500->mutex); ++ sel->r = *__imx500_get_pad_crop(imx500, sd_state, sel->pad, ++ sel->which); ++ mutex_unlock(&imx500->mutex); ++ ++ return 0; ++ } ++ ++ case V4L2_SEL_TGT_NATIVE_SIZE: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = IMX500_NATIVE_WIDTH; ++ sel->r.height = IMX500_NATIVE_HEIGHT; ++ ++ return 0; ++ ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = IMX500_PIXEL_ARRAY_LEFT; ++ sel->r.top = IMX500_PIXEL_ARRAY_TOP; ++ sel->r.width = IMX500_PIXEL_ARRAY_WIDTH; ++ sel->r.height = IMX500_PIXEL_ARRAY_HEIGHT; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int __must_check imx500_spi_write(struct imx500 *state, const u8 *data, ++ size_t size) ++{ ++ if (size % 4 || size > ONE_MIB) ++ return -EINVAL; ++ ++ if (!state->spi_device) ++ return -ENODEV; ++ ++ return spi_write(state->spi_device, data, size); ++} ++ ++/* Moves the IMX500 internal state machine between states or updates. ++ * ++ * Prerequisites: Sensor is powered on and not currently streaming ++ */ ++static int imx500_state_transition(struct imx500 *imx500, const u8 *fw, ++ size_t fw_size, enum imx500_image_type type, ++ bool update) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ struct cci_reg_sequence cmd_reply_sts_cnt_reg; ++ size_t valid_size; ++ int ret; ++ u64 tmp; ++ ++ if (!imx500 || !fw || type >= TYPE_MAX) ++ return -EINVAL; ++ ++ if (!update && (int)type != (int)imx500->fsm_state) ++ return -EINVAL; ++ ++ /* Validate firmware */ ++ valid_size = imx500_valid_fw_bytes(fw, fw_size); ++ if (!valid_size) ++ return -EINVAL; ++ ++ ret = imx500_prepare_poll_cmd_reply_sts(imx500, &cmd_reply_sts_cnt_reg); ++ if (ret) ++ return ret; ++ ++ struct cci_reg_sequence common_regs[] = { ++ { IMX500_REG_DD_FLASH_TYPE, 0x02 }, ++ { IMX500_REG_DD_LOAD_MODE, IMX500_DD_LOAD_MODE_AP }, ++ { IMX500_REG_DD_IMAGE_TYPE, type }, ++ { IMX500_REG_DD_DOWNLOAD_DIV_NUM, (valid_size - 1) / ONE_MIB }, ++ { IMX500_REG_DD_DOWNLOAD_FILE_SIZE, valid_size }, ++ }; ++ ++ struct cci_reg_sequence state_transition_regs[] = { ++ { IMX500_REG_DD_ST_TRANS_CMD, type }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_ST_TRANS }, ++ }; ++ ++ struct cci_reg_sequence update_regs[] = { ++ { IMX500_REG_DD_UPDATE_CMD, IMX500_DD_UPDATE_CMD_SRAM }, ++ { IMX500_REG_DD_CMD_INT, IMX500_DD_CMD_INT_UPDATE }, ++ }; ++ ++ ret = cci_multi_reg_write(imx500->regmap, common_regs, ++ ARRAY_SIZE(common_regs), NULL); ++ ++ cci_multi_reg_write(imx500->regmap, ++ update ? update_regs : state_transition_regs, 2, ++ &ret); ++ if (ret) ++ return ret; ++ ++ /* Poll CMD_REPLY_STS_CNT until a response is available */ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) { ++ dev_err(&client->dev, "DD_REF_STS register did not update\n"); ++ return ret; ++ } ++ ++ /* Read response to state transition / update request */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &tmp, NULL); ++ if (ret || tmp != (update ? IMX500_DD_CMD_REPLY_STS_UPDATE_READY : ++ IMX500_DD_CMD_REPLY_STS_TRANS_READY)) ++ return ret ? ret : -EBUSY; ++ ++ imx500->fw_stage = type; ++ imx500->fw_progress = 0; ++ ++ for (size_t i = 0; i <= valid_size / ONE_MIB; i++) { ++ const u8 *data = fw + (i * ONE_MIB); ++ size_t size = valid_size - (i * ONE_MIB); ++ struct cci_reg_sequence download_sts_reg = { ++ IMX500_REG_DD_DOWNLOAD_STS, ++ IMX500_DD_DOWNLOAD_STS_DOWNLOADING, ++ }; ++ ++ /* Calculate SPI xfer size avoiding 0-sized TXNs */ ++ size = min_t(size_t, size, ONE_MIB); ++ if (!size) ++ break; ++ ++ /* Poll until device is ready for download */ ++ ret = imx500_poll_status_reg(imx500, &download_sts_reg, 100); ++ if (ret) { ++ dev_err(&client->dev, ++ "DD_DOWNLOAD_STS was never ready\n"); ++ return ret; ++ } ++ ++ /* Do SPI transfer */ ++ gpiod_set_value_cansleep(imx500->led_gpio, 1); ++ ret = imx500_spi_write(imx500, data, size); ++ gpiod_set_value_cansleep(imx500->led_gpio, 0); ++ ++ imx500->fw_progress += size; ++ ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Poll until another response is available */ ++ ret = imx500_poll_status_reg(imx500, &cmd_reply_sts_cnt_reg, 5); ++ if (ret) { ++ dev_err(&client->dev, ++ "DD_REF_STS register did not update after SPI write(s)\n"); ++ return ret; ++ } ++ ++ /* Verify that state transition / update completed successfully */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_CMD_REPLY_STS, &tmp, NULL); ++ if (ret || tmp != (update ? IMX500_DD_CMD_REPLY_STS_UPDATE_DONE : ++ IMX500_DD_CMD_REPLY_STS_TRANS_DONE)) ++ return ret ? ret : -EREMOTEIO; ++ ++ if (!update && imx500->fsm_state < IMX500_STATE_WITH_NETWORK) ++ imx500->fsm_state++; ++ ++ imx500->fw_progress = fw_size; ++ ++ return 0; ++} ++ ++static int imx500_transition_to_standby_wo_network(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ const struct firmware *firmware; ++ u64 fw_ver; ++ int ret; ++ ++ firmware = imx500->fw_loader; ++ ret = imx500_state_transition(imx500, firmware->data, firmware->size, ++ TYPE_LOADER, false); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load loader firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ firmware = imx500->fw_main; ++ ret = imx500_state_transition(imx500, firmware->data, firmware->size, ++ TYPE_MAIN, false); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load main firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_MAIN_FW_VERSION, &fw_ver, ++ NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: could not read main firmware version\n", __func__); ++ return ret; ++ } ++ ++ dev_info(&client->dev, ++ "main firmware version: %llu%llu.%llu%llu.%llu%llu\n", ++ (fw_ver >> 20) & 0xF, (fw_ver >> 16) & 0xF, ++ (fw_ver >> 12) & 0xF, (fw_ver >> 8) & 0xF, (fw_ver >> 4) & 0xF, ++ fw_ver & 0xF); ++ ++ ret = cci_multi_reg_write(imx500->regmap, metadata_output, ++ ARRAY_SIZE(metadata_output), NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: failed to configure MIPI output for DNN\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = cci_multi_reg_write(imx500->regmap, dnn_regs, ++ ARRAY_SIZE(dnn_regs), NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s: unable to write DNN regs\n", ++ __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int imx500_transition_to_network(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ u64 imx500_fsm_state; ++ int ret; ++ ++ ret = imx500_iterate_nw_regs(imx500->fw_network, ++ imx500->fw_network_size, imx500, ++ imx500_reg_val_write_cbk); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s: unable to apply register writes from firmware\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Read IMX500 state to determine whether transition or update is required */ ++ ret = cci_read(imx500->regmap, IMX500_REG_DD_SYS_STATE, ++ &imx500_fsm_state, NULL); ++ if (ret || imx500_fsm_state & 1) ++ return ret ? ret : -EREMOTEIO; ++ ++ ret = imx500_state_transition( ++ imx500, imx500->fw_network, imx500->fw_network_size, ++ TYPE_NW_WEIGHTS, ++ imx500_fsm_state == IMX500_DD_SYS_STATE_STANDBY_WITH_NETWORK); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to load network weights\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Select network 0 */ ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD701), 0, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to select network 0\n", ++ __func__); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++/* Start streaming */ ++static int imx500_start_streaming(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ const struct imx500_reg_list *reg_list; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(&client->dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = cci_write(imx500->regmap, IMX500_REG_IMAGE_ONLY_MODE, ++ imx500->fw_network ? IMX500_IMAGE_ONLY_FALSE : ++ IMX500_IMAGE_ONLY_TRUE, ++ NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set image mode\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Acquire loader and main firmware if needed */ ++ if (imx500->fw_network) { ++ if (!imx500->fw_loader) { ++ ret = request_firmware(&imx500->fw_loader, ++ "imx500_loader.fpk", ++ &client->dev); ++ if (ret) { ++ dev_err(&client->dev, ++ "Unable to acquire firmware loader\n"); ++ return ret; ++ } ++ } ++ if (!imx500->fw_main) { ++ ret = request_firmware(&imx500->fw_main, ++ "imx500_firmware.fpk", ++ &client->dev); ++ if (ret) { ++ dev_err(&client->dev, ++ "Unable to acquire main firmware\n"); ++ return ret; ++ } ++ } ++ } ++ ++ if (!imx500->common_regs_written) { ++ ret = cci_multi_reg_write(imx500->regmap, mode_common_regs, ++ ARRAY_SIZE(mode_common_regs), NULL); ++ ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to set common settings\n", __func__); ++ return ret; ++ } ++ ++ imx500->common_regs_written = true; ++ } ++ ++ if (imx500->fw_network && !imx500->loader_and_main_written) { ++ ret = imx500_transition_to_standby_wo_network(imx500); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to transition from program empty state\n", ++ __func__); ++ return ret; ++ } ++ imx500->loader_and_main_written = true; ++ } ++ ++ if (imx500->fw_network && !imx500->network_written) { ++ ret = imx500_transition_to_network(imx500); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s failed to transition to network loaded\n", ++ __func__); ++ return ret; ++ } ++ imx500->network_written = true; ++ } ++ ++ /* Enable DNN */ ++ if (imx500->fw_network) { ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD100), 4, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to enable DNN\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ /* Apply default values of current mode */ ++ reg_list = &imx500->mode->reg_list; ++ ret = cci_multi_reg_write(imx500->regmap, reg_list->regs, ++ reg_list->num_of_regs, NULL); ++ if (ret) { ++ dev_err(&client->dev, "%s failed to set mode\n", __func__); ++ return ret; ++ } ++ ++ /* Apply customized values from user */ ++ ret = __v4l2_ctrl_handler_setup(imx500->sd.ctrl_handler); ++ ++ /* Disable any sensor startup frame drops. This must be written here! */ ++ cci_write(imx500->regmap, CCI_REG8(0xD405), 0, &ret); ++ ++ /* set stream on register */ ++ cci_write(imx500->regmap, IMX500_REG_MODE_SELECT, IMX500_MODE_STREAMING, ++ &ret); ++ ++ return ret; ++} ++ ++/* Stop streaming */ ++static void imx500_stop_streaming(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret; ++ ++ /* set stream off register */ ++ ret = cci_write(imx500->regmap, IMX500_REG_MODE_SELECT, ++ IMX500_MODE_STANDBY, NULL); ++ if (ret) ++ dev_err(&client->dev, "%s failed to set stream\n", __func__); ++ ++ /* Disable DNN */ ++ ret = cci_write(imx500->regmap, CCI_REG8(0xD100), 0, NULL); ++ if (ret) ++ dev_err(&client->dev, "%s failed to disable DNN\n", __func__); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++} ++ ++static int imx500_set_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx500 *imx500 = to_imx500(sd); ++ int ret = 0; ++ ++ mutex_lock(&imx500->mutex); ++ if (imx500->streaming == enable) { ++ mutex_unlock(&imx500->mutex); ++ return 0; ++ } ++ ++ if (enable) { ++ /* ++ * Apply default & customized values ++ * and then start streaming. ++ */ ++ ret = imx500_start_streaming(imx500); ++ if (ret) ++ goto err_start_streaming; ++ } else { ++ imx500_stop_streaming(imx500); ++ } ++ ++ imx500->streaming = enable; ++ ++ /* vflip and hflip cannot change during streaming */ ++ __v4l2_ctrl_grab(imx500->vflip, enable); ++ __v4l2_ctrl_grab(imx500->hflip, enable); ++ __v4l2_ctrl_grab(imx500->network_fw_ctrl, enable); ++ ++ mutex_unlock(&imx500->mutex); ++ ++ return ret; ++ ++err_start_streaming: ++ mutex_unlock(&imx500->mutex); ++ ++ return ret; ++} ++ ++/* Power/clock management functions */ ++static int imx500_power_on(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ int ret; ++ ++ ret = regulator_bulk_enable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ return ret; ++ } ++ ++ /* T4 - 1us ++ * Ambiguous: Regulators rising to INCK start is specified by the datasheet ++ * but also "Presence of INCK during Power off is acceptable" ++ */ ++ udelay(2); ++ ++ ret = clk_prepare_enable(imx500->xclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", __func__); ++ goto reg_off; ++ } ++ ++ /* T5 - 0ms ++ * Ambiguous: Regulators rising to XCLR rising is specified by the datasheet ++ * as 0ms but also "XCLR pin should be set to 'High' after INCK supplied.". ++ * T4 and T5 are shown as overlapping. ++ */ ++ gpiod_set_value_cansleep(imx500->reset_gpio, 1); ++ ++ /* T7 - 9ms ++ * "INCK start and CXLR rising till Send Streaming Command wait time" ++ */ ++ usleep_range(9000, 12000); ++ ++ return 0; ++ ++reg_off: ++ regulator_bulk_disable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ return ret; ++} ++ ++static int imx500_power_off(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ /* Datasheet specifies power down sequence as INCK disable, XCLR low, ++ * regulator disable. T1 (XCLR neg-edge to regulator disable) is specified ++ * as 0us. ++ * ++ * Note, this is not the reverse order of power up. ++ */ ++ clk_disable_unprepare(imx500->xclk); ++ gpiod_set_value_cansleep(imx500->reset_gpio, 0); ++ regulator_bulk_disable(IMX500_NUM_SUPPLIES, imx500->supplies); ++ ++ /* Force reprogramming of the common registers when powered up again. */ ++ imx500->fsm_state = IMX500_STATE_RESET; ++ imx500->common_regs_written = false; ++ imx500->loader_and_main_written = false; ++ imx500_clear_fw_network(imx500); ++ ++ return 0; ++} ++ ++static int imx500_get_regulators(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ unsigned int i; ++ ++ for (i = 0; i < IMX500_NUM_SUPPLIES; i++) ++ imx500->supplies[i].supply = imx500_supply_name[i]; ++ ++ return devm_regulator_bulk_get(&client->dev, IMX500_NUM_SUPPLIES, ++ imx500->supplies); ++} ++ ++/* Verify chip ID */ ++static int imx500_identify_module(struct imx500 *imx500) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ int ret; ++ u64 val; ++ ++ ret = cci_read(imx500->regmap, IMX500_REG_CHIP_ID, &val, NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "failed to read chip id %x, with error %d\n", ++ IMX500_CHIP_ID, ret); ++ return ret; ++ } ++ ++ if (val != IMX500_CHIP_ID) { ++ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", ++ IMX500_CHIP_ID, val); ++ return -EIO; ++ } ++ ++ dev_info(&client->dev, "Device found is imx%llx\n", val); ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops imx500_core_ops = { ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static const struct v4l2_subdev_video_ops imx500_video_ops = { ++ .s_stream = imx500_set_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx500_pad_ops = { ++ .enum_mbus_code = imx500_enum_mbus_code, ++ .get_fmt = imx500_get_pad_format, ++ .set_fmt = imx500_set_pad_format, ++ .get_selection = imx500_get_selection, ++ .enum_frame_size = imx500_enum_frame_size, ++}; ++ ++static const struct v4l2_subdev_ops imx500_subdev_ops = { ++ .core = &imx500_core_ops, ++ .video = &imx500_video_ops, ++ .pad = &imx500_pad_ops, ++}; ++ ++static const s64 imx500_link_freq_menu[] = { ++ IMX500_DEFAULT_LINK_FREQ, ++}; ++ ++/* Custom control for inference window */ ++static const struct v4l2_ctrl_config inf_window_ctrl = { ++ .name = "IMX500 Inference Windows", ++ .id = V4L2_CID_USER_IMX500_INFERENCE_WINDOW, ++ .dims[0] = 4, ++ .ops = &imx500_ctrl_ops, ++ .type = V4L2_CTRL_TYPE_U32, ++ .elem_size = sizeof(u32), ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE | ++ V4L2_CTRL_FLAG_HAS_PAYLOAD, ++ .def = 0, ++ .min = 0x00, ++ .max = 4032, ++ .step = 1, ++}; ++ ++/* Custom control for network firmware file FD */ ++static const struct v4l2_ctrl_config network_fw_fd = { ++ .name = "IMX500 Network Firmware File FD", ++ .id = V4L2_CID_USER_IMX500_NETWORK_FW_FD, ++ .ops = &imx500_ctrl_ops, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE | ++ V4L2_CTRL_FLAG_WRITE_ONLY, ++ .min = -1, ++ .max = S32_MAX, ++ .step = 1, ++ .def = -1, ++}; ++ ++/* Initialize control handlers */ ++static int imx500_init_controls(struct imx500 *imx500) ++{ ++ struct v4l2_ctrl_handler *ctrl_hdlr; ++ struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd); ++ struct v4l2_fwnode_device_properties props; ++ int ret; ++ ++ ctrl_hdlr = &imx500->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); ++ if (ret) ++ return ret; ++ ++ mutex_init(&imx500->mutex); ++ ctrl_hdlr->lock = &imx500->mutex; ++ ++ /* By default, PIXEL_RATE is read only */ ++ imx500->pixel_rate = v4l2_ctrl_new_std( ++ ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_PIXEL_RATE, ++ IMX500_PIXEL_RATE, IMX500_PIXEL_RATE, 1, IMX500_PIXEL_RATE); ++ ++ /* LINK_FREQ is also read only */ ++ imx500->link_freq = ++ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(imx500_link_freq_menu) - 1, 0, ++ imx500_link_freq_menu); ++ if (imx500->link_freq) ++ imx500->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ ++ /* ++ * Create the controls here, but mode specific limits are setup ++ * in the imx500_set_framing_limits() call below. ++ */ ++ imx500->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_VBLANK, IMX500_VBLANK_MIN, ++ 0xffff, 1, IMX500_VBLANK_MIN); ++ imx500->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_HBLANK, 0, 0xffff, 1, 0); ++ ++ imx500->exposure = v4l2_ctrl_new_std( ++ ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_EXPOSURE, ++ IMX500_EXPOSURE_MIN, IMX500_EXPOSURE_MAX, IMX500_EXPOSURE_STEP, ++ IMX500_EXPOSURE_DEFAULT); ++ ++ v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, ++ IMX500_ANA_GAIN_MIN, IMX500_ANA_GAIN_MAX, ++ IMX500_ANA_GAIN_STEP, IMX500_ANA_GAIN_DEFAULT); ++ ++ imx500->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ if (imx500->hflip) ++ imx500->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ imx500->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ if (imx500->vflip) ++ imx500->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ++ ++ v4l2_ctrl_new_custom(ctrl_hdlr, &imx500_notify_gains_ctrl, NULL); ++ v4l2_ctrl_new_custom(ctrl_hdlr, &inf_window_ctrl, NULL); ++ imx500->network_fw_ctrl = ++ v4l2_ctrl_new_custom(ctrl_hdlr, &network_fw_fd, NULL); ++ ++ if (ctrl_hdlr->error) { ++ ret = ctrl_hdlr->error; ++ dev_err(&client->dev, "%s control init failed (%d)\n", __func__, ++ ret); ++ goto error; ++ } ++ ++ ret = v4l2_fwnode_device_parse(&client->dev, &props); ++ if (ret) ++ goto error; ++ ++ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx500_ctrl_ops, ++ &props); ++ if (ret) ++ goto error; ++ ++ imx500->sd.ctrl_handler = ctrl_hdlr; ++ ++ /* Setup exposure and frame/line length limits. */ ++ imx500_set_framing_limits(imx500); ++ ++ return 0; ++ ++error: ++ v4l2_ctrl_handler_free(ctrl_hdlr); ++ mutex_destroy(&imx500->mutex); ++ ++ return ret; ++} ++ ++static void imx500_free_controls(struct imx500 *imx500) ++{ ++ v4l2_ctrl_handler_free(imx500->sd.ctrl_handler); ++ mutex_destroy(&imx500->mutex); ++} ++ ++static int imx500_check_hwcfg(struct device *dev) ++{ ++ struct fwnode_handle *endpoint; ++ struct v4l2_fwnode_endpoint ep_cfg = { .bus_type = ++ V4L2_MBUS_CSI2_DPHY }; ++ int ret = -EINVAL; ++ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); ++ if (!endpoint) { ++ dev_err(dev, "endpoint node not found\n"); ++ return -EINVAL; ++ } ++ ++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { ++ dev_err(dev, "could not parse endpoint\n"); ++ goto error_out; ++ } ++ ++ /* Check the number of MIPI CSI2 data lanes */ ++ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { ++ dev_err(dev, "only 2 data lanes are currently supported\n"); ++ goto error_out; ++ } ++ ++ /* Check the link frequency set in device tree */ ++ if (!ep_cfg.nr_of_link_frequencies) { ++ dev_err(dev, "link-frequency property not found in DT\n"); ++ goto error_out; ++ } ++ ++ if (ep_cfg.nr_of_link_frequencies != 1 || ++ ep_cfg.link_frequencies[0] != IMX500_DEFAULT_LINK_FREQ) { ++ dev_err(dev, "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies[0]); ++ goto error_out; ++ } ++ ++ ret = 0; ++ ++error_out: ++ v4l2_fwnode_endpoint_free(&ep_cfg); ++ fwnode_handle_put(endpoint); ++ ++ return ret; ++} ++ ++static int fw_progress_show(struct seq_file *s, void *data) ++{ ++ struct imx500 *imx500 = s->private; ++ ++ seq_printf(s, "%d %zu %zu\n", imx500->fw_stage, imx500->fw_progress, ++ imx500->fw_network_size); ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(fw_progress); ++ ++static int imx500_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct spi_device *spi = NULL; ++ char debugfs_name[128]; ++ struct imx500 *imx500; ++ int ret; ++ ++ struct device_node *spi_node = of_parse_phandle(dev->of_node, "spi", 0); ++ ++ if (spi_node) { ++ struct device *tmp = ++ bus_find_device_by_of_node(&spi_bus_type, spi_node); ++ of_node_put(spi_node); ++ spi = tmp ? to_spi_device(tmp) : NULL; ++ if (!spi) ++ return -EPROBE_DEFER; ++ } ++ ++ imx500 = devm_kzalloc(&client->dev, sizeof(*imx500), GFP_KERNEL); ++ if (!imx500) ++ return -ENOMEM; ++ ++ imx500->regmap = devm_cci_regmap_init_i2c(client, 16); ++ if (IS_ERR(imx500->regmap)) ++ return dev_err_probe(dev, PTR_ERR(imx500->regmap), ++ "failed to initialise CCI\n"); ++ ++ imx500->spi_device = spi; ++ ++ v4l2_i2c_subdev_init(&imx500->sd, client, &imx500_subdev_ops); ++ ++ /* Check the hardware configuration in device tree */ ++ if (imx500_check_hwcfg(dev)) ++ return -EINVAL; ++ ++ /* Get system clock (xclk) */ ++ imx500->xclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(imx500->xclk)) ++ return dev_err_probe(dev, PTR_ERR(imx500->xclk), ++ "failed to get xclk\n"); ++ ++ imx500->xclk_freq = clk_get_rate(imx500->xclk); ++ if (imx500->xclk_freq != IMX500_XCLK_FREQ) { ++ dev_err(dev, "xclk frequency not supported: %d Hz\n", ++ imx500->xclk_freq); ++ return -EINVAL; ++ } ++ ++ ret = imx500_get_regulators(imx500); ++ if (ret) { ++ dev_err(dev, "failed to get regulators\n"); ++ return ret; ++ } ++ ++ imx500->led_gpio = devm_gpiod_get_optional(dev, "led", GPIOD_OUT_LOW); ++ ++ imx500->reset_gpio = ++ devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); ++ ++ /* ++ * The sensor must be powered for imx500_identify_module() ++ * to be able to read the CHIP_ID register ++ */ ++ ret = imx500_power_on(dev); ++ if (ret) ++ return ret; ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_get_noresume(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, 5000); ++ pm_runtime_use_autosuspend(dev); ++ ++ ret = imx500_identify_module(imx500); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize default format */ ++ imx500_set_default_format(imx500); ++ ++ /* This needs the pm runtime to be registered. */ ++ ret = imx500_init_controls(imx500); ++ if (ret) ++ goto error_power_off; ++ ++ /* Initialize subdev */ ++ imx500->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | ++ V4L2_SUBDEV_FL_HAS_EVENTS; ++ imx500->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ++ /* Initialize source pads */ ++ imx500->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ imx500->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&imx500->sd.entity, NUM_PADS, imx500->pad); ++ if (ret) { ++ dev_err(dev, "failed to init entity pads: %d\n", ret); ++ goto error_handler_free; ++ } ++ ++ ret = v4l2_async_register_subdev_sensor(&imx500->sd); ++ if (ret < 0) { ++ dev_err(dev, "failed to register sensor sub-device: %d\n", ret); ++ goto error_media_entity; ++ } ++ ++ snprintf(debugfs_name, sizeof(debugfs_name), "imx500-fw:%s", ++ dev_name(dev)); ++ imx500->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("fw_progress", 0444, imx500->debugfs, imx500, ++ &fw_progress_fops); ++ ++ pm_runtime_mark_last_busy(&client->dev); ++ pm_runtime_put_autosuspend(&client->dev); ++ ++ return 0; ++ ++error_media_entity: ++ media_entity_cleanup(&imx500->sd.entity); ++ ++error_handler_free: ++ imx500_free_controls(imx500); ++ ++error_power_off: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_put_noidle(&client->dev); ++ imx500_power_off(&client->dev); ++ ++ return ret; ++} ++ ++static void imx500_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx500 *imx500 = to_imx500(sd); ++ ++ if (imx500->spi_device) ++ put_device(&imx500->spi_device->dev); ++ ++ v4l2_async_unregister_subdev(sd); ++ media_entity_cleanup(&sd->entity); ++ imx500_free_controls(imx500); ++ ++ if (imx500->fw_loader) ++ release_firmware(imx500->fw_loader); ++ ++ if (imx500->fw_main) ++ release_firmware(imx500->fw_main); ++ ++ imx500->fw_loader = NULL; ++ imx500->fw_main = NULL; ++ imx500_clear_fw_network(imx500); ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ imx500_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct of_device_id imx500_dt_ids[] = { ++ { .compatible = "sony,imx500" }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, imx500_dt_ids); ++ ++static const struct dev_pm_ops imx500_pm_ops = { SET_RUNTIME_PM_OPS( ++ imx500_power_off, imx500_power_on, NULL) }; ++ ++static struct i2c_driver imx500_i2c_driver = { ++ .driver = { ++ .name = "imx500", ++ .of_match_table = imx500_dt_ids, ++ .pm = &imx500_pm_ops, ++ }, ++ .probe = imx500_probe, ++ .remove = imx500_remove, ++}; ++ ++static int imx500_spi_probe(struct spi_device *spi) ++{ ++ int result; ++ ++ spi->bits_per_word = 8; ++ spi->max_speed_hz = 35000000; ++ spi->mode = SPI_MODE_3; ++ ++ result = spi_setup(spi); ++ if (result < 0) ++ return dev_err_probe(&spi->dev, result, "spi_setup() failed"); ++ ++ return 0; ++} ++ ++static void imx500_spi_remove(struct spi_device *spi) ++{ ++} ++ ++static const struct spi_device_id imx500_spi_id[] = { ++ { "imx500", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(spi, imx500_spi_id); ++ ++static struct spi_driver imx500_spi_driver = { ++ .driver = { ++ .name = "imx500", ++ .of_match_table = imx500_dt_ids, ++ }, ++ .probe = imx500_spi_probe, ++ .remove = imx500_spi_remove, ++ .id_table = imx500_spi_id, ++}; ++ ++static int __init imx500_driver_init(void) ++{ ++ int ret; ++ ++ ret = spi_register_driver(&imx500_spi_driver); ++ if (ret) ++ return ret; ++ ++ ret = i2c_add_driver(&imx500_i2c_driver); ++ if (ret) ++ spi_unregister_driver(&imx500_spi_driver); ++ ++ return ret; ++} ++module_init(imx500_driver_init); ++ ++static void __exit imx500_driver_exit(void) ++{ ++ i2c_del_driver(&imx500_i2c_driver); ++ spi_unregister_driver(&imx500_spi_driver); ++} ++module_exit(imx500_driver_exit); ++ ++MODULE_AUTHOR("Naushir Patuck "); ++MODULE_DESCRIPTION("Sony IMX500 sensor driver"); ++MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx519.c b/drivers/media/i2c/imx519.c new file mode 100644 index 000000000000..7cb63e018764 @@ -119843,7 +126488,7 @@ index 000000000000..fa5bb797d3d6 +MODULE_DESCRIPTION("OmniVision OV2311 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c -index 8de398423b7c..3f89974963e0 100644 +index 8de398423b7c..f474d22dbded 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -20,6 +20,7 @@ @@ -119854,8 +126499,12 @@ index 8de398423b7c..3f89974963e0 100644 #include #include #include -@@ -54,6 +55,8 @@ +@@ -52,8 +53,12 @@ + #define OV5647_REG_AEC_AGC 0x3503 + #define OV5647_REG_GAIN_HI 0x350a #define OV5647_REG_GAIN_LO 0x350b ++#define OV5647_REG_HTS_HI 0x380c ++#define OV5647_REG_HTS_LO 0x380d #define OV5647_REG_VTS_HI 0x380e #define OV5647_REG_VTS_LO 0x380f +#define OV5647_REG_VFLIP 0x3820 @@ -119863,7 +126512,7 @@ index 8de398423b7c..3f89974963e0 100644 #define OV5647_REG_FRAME_OFF_NUMBER 0x4202 #define OV5647_REG_MIPI_CTRL00 0x4800 #define OV5647_REG_MIPI_CTRL14 0x4814 -@@ -69,11 +72,11 @@ +@@ -69,18 +74,36 @@ #define OV5647_NATIVE_HEIGHT 1956U #define OV5647_PIXEL_ARRAY_LEFT 16U @@ -119876,8 +126525,10 @@ index 8de398423b7c..3f89974963e0 100644 +#define OV5647_VBLANK_MIN 24 #define OV5647_VTS_MAX 32767 ++#define OV5647_HTS_MAX 0x1fff ++ #define OV5647_EXPOSURE_MIN 4 -@@ -81,6 +84,15 @@ + #define OV5647_EXPOSURE_STEP 1 #define OV5647_EXPOSURE_DEFAULT 1000 #define OV5647_EXPOSURE_MAX 65535 @@ -119889,11 +126540,26 @@ index 8de398423b7c..3f89974963e0 100644 +}; + +#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names) ++ ++#define FREQ_INDEX_FULL 0 ++#define FREQ_INDEX_VGA 1 ++static const s64 ov5647_link_freqs[] = { ++ [FREQ_INDEX_FULL] = 218500000, ++ [FREQ_INDEX_VGA] = 208333000, ++}; + struct regval_list { u16 addr; u8 data; -@@ -102,6 +114,7 @@ struct ov5647 { +@@ -90,6 +113,7 @@ struct ov5647_mode { + struct v4l2_mbus_framefmt format; + struct v4l2_rect crop; + u64 pixel_rate; ++ unsigned int link_freq_index; + int hts; + int vts; + const struct regval_list *reg_list; +@@ -102,6 +126,7 @@ struct ov5647 { struct mutex lock; struct clk *xclk; struct gpio_desc *pwdn; @@ -119901,52 +126567,402 @@ index 8de398423b7c..3f89974963e0 100644 bool clock_ncont; struct v4l2_ctrl_handler ctrls; const struct ov5647_mode *mode; -@@ -109,6 +122,8 @@ struct ov5647 { +@@ -109,6 +134,9 @@ struct ov5647 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *link_freq; bool streaming; }; -@@ -151,7 +166,7 @@ static struct regval_list ov5647_2592x1944_10bpp[] = { - {0x3036, 0x69}, +@@ -143,22 +171,16 @@ static const struct regval_list sensor_oe_enable_regs[] = { + {0x3002, 0xe4}, + }; + +-static struct regval_list ov5647_2592x1944_10bpp[] = { ++static struct regval_list ov5647_common_regs[] = { + {0x0100, 0x00}, + {0x0103, 0x01}, + {0x3034, 0x1a}, + {0x3035, 0x21}, +- {0x3036, 0x69}, {0x303c, 0x11}, {0x3106, 0xf5}, - {0x3821, 0x06}, -+ {0x3821, 0x00}, - {0x3820, 0x00}, +- {0x3820, 0x00}, {0x3827, 0xec}, {0x370c, 0x03}, -@@ -240,7 +255,7 @@ static struct regval_list ov5647_1080p30_10bpp[] = { - {0x3036, 0x62}, - {0x303c, 0x11}, - {0x3106, 0xf5}, -- {0x3821, 0x06}, +- {0x3612, 0x5b}, +- {0x3618, 0x04}, + {0x5000, 0x06}, +- {0x5002, 0x41}, + {0x5003, 0x08}, + {0x5a00, 0x08}, + {0x3000, 0x00}, +@@ -173,26 +195,6 @@ static struct regval_list ov5647_2592x1944_10bpp[] = { + {0x3a19, 0xf8}, + {0x3c01, 0x80}, + {0x3b07, 0x0c}, +- {0x380c, 0x0b}, +- {0x380d, 0x1c}, +- {0x3814, 0x11}, +- {0x3815, 0x11}, +- {0x3708, 0x64}, +- {0x3709, 0x12}, +- {0x3808, 0x0a}, +- {0x3809, 0x20}, +- {0x380a, 0x07}, +- {0x380b, 0x98}, +- {0x3800, 0x00}, +- {0x3801, 0x00}, +- {0x3802, 0x00}, +- {0x3803, 0x00}, +- {0x3804, 0x0a}, +- {0x3805, 0x3f}, +- {0x3806, 0x07}, +- {0x3807, 0xa3}, +- {0x3811, 0x10}, +- {0x3813, 0x06}, + {0x3630, 0x2e}, + {0x3632, 0xe2}, + {0x3633, 0x23}, +@@ -212,11 +214,6 @@ static struct regval_list ov5647_2592x1944_10bpp[] = { + {0x3f06, 0x10}, + {0x3f01, 0x0a}, + {0x3a08, 0x01}, +- {0x3a09, 0x28}, +- {0x3a0a, 0x00}, +- {0x3a0b, 0xf6}, +- {0x3a0d, 0x08}, +- {0x3a0e, 0x06}, + {0x3a0f, 0x58}, + {0x3a10, 0x50}, + {0x3a1b, 0x58}, +@@ -224,54 +221,57 @@ static struct regval_list ov5647_2592x1944_10bpp[] = { + {0x3a11, 0x60}, + {0x3a1f, 0x28}, + {0x4001, 0x02}, +- {0x4004, 0x04}, + {0x4000, 0x09}, ++ {0x3503, 0x03}, ++}; ++ ++static struct regval_list ov5647_2592x1944_10bpp[] = { ++ {0x3036, 0x69}, + {0x3821, 0x00}, - {0x3820, 0x00}, - {0x3827, 0xec}, - {0x370c, 0x03}, -@@ -404,7 +419,7 @@ static struct regval_list ov5647_2x2binned_10bpp[] = { ++ {0x3820, 0x00}, ++ {0x3612, 0x5b}, ++ {0x3618, 0x04}, ++ {0x5002, 0x41}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ {0x3708, 0x64}, ++ {0x3709, 0x12}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x00}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0xa3}, ++ {0x3808, 0x0a}, ++ {0x3809, 0x20}, ++ {0x380a, 0x07}, ++ {0x380b, 0x98}, ++ {0x3811, 0x10}, ++ {0x3813, 0x06}, ++ {0x3a09, 0x28}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x08}, ++ {0x3a0e, 0x06}, ++ {0x4004, 0x04}, + {0x4837, 0x19}, {0x4800, 0x24}, - {0x3503, 0x03}, - {0x3820, 0x41}, -- {0x3821, 0x07}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + + static struct regval_list ov5647_1080p30_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3034, 0x1a}, +- {0x3035, 0x21}, +- {0x3036, 0x62}, +- {0x303c, 0x11}, +- {0x3106, 0xf5}, +- {0x3821, 0x06}, ++ {0x3036, 0x69}, ++ {0x3821, 0x00}, + {0x3820, 0x00}, +- {0x3827, 0xec}, +- {0x370c, 0x03}, + {0x3612, 0x5b}, + {0x3618, 0x04}, +- {0x5000, 0x06}, + {0x5002, 0x41}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3016, 0x08}, +- {0x3017, 0xe0}, +- {0x3018, 0x44}, +- {0x301c, 0xf8}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, +- {0x380c, 0x09}, +- {0x380d, 0x70}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3708, 0x64}, + {0x3709, 0x12}, +- {0x3808, 0x07}, +- {0x3809, 0x80}, +- {0x380a, 0x04}, +- {0x380b, 0x38}, + {0x3800, 0x01}, + {0x3801, 0x5c}, + {0x3802, 0x01}, +@@ -280,75 +280,30 @@ static struct regval_list ov5647_1080p30_10bpp[] = { + {0x3805, 0xe3}, + {0x3806, 0x05}, + {0x3807, 0xf1}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, + {0x3811, 0x04}, + {0x3813, 0x02}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3636, 0x06}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, + {0x3a09, 0x4b}, + {0x3a0a, 0x01}, + {0x3a0b, 0x13}, + {0x3a0d, 0x04}, + {0x3a0e, 0x03}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x04}, +- {0x4000, 0x09}, + {0x4837, 0x19}, + {0x4800, 0x34}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + + static struct regval_list ov5647_2x2binned_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3034, 0x1a}, +- {0x3035, 0x21}, +- {0x3036, 0x62}, +- {0x303c, 0x11}, +- {0x3106, 0xf5}, +- {0x3827, 0xec}, +- {0x370c, 0x03}, ++ {0x3036, 0x69}, + {0x3821, 0x01}, ++ {0x3820, 0x41}, + {0x3612, 0x59}, + {0x3618, 0x00}, +- {0x5000, 0x06}, + {0x5002, 0x41}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3016, 0x08}, +- {0x3017, 0xe0}, +- {0x3018, 0x44}, +- {0x301c, 0xf8}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, +@@ -361,50 +316,18 @@ static struct regval_list ov5647_2x2binned_10bpp[] = { + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, +- {0x380c, 0x07}, +- {0x380d, 0x68}, + {0x3811, 0x0c}, + {0x3813, 0x06}, + {0x3814, 0x31}, + {0x3815, 0x31}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3636, 0x06}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, + {0x3a09, 0x28}, + {0x3a0a, 0x00}, + {0x3a0b, 0xf6}, + {0x3a0d, 0x08}, + {0x3a0e, 0x06}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x04}, +- {0x4000, 0x09}, + {0x4837, 0x16}, + {0x4800, 0x24}, +- {0x3503, 0x03}, +- {0x3820, 0x41}, +- {0x3821, 0x07}, {0x350a, 0x00}, {0x350b, 0x10}, {0x3500, 0x00}, -@@ -420,7 +435,7 @@ static struct regval_list ov5647_640x480_10bpp[] = { - {0x3035, 0x11}, +@@ -415,37 +338,15 @@ static struct regval_list ov5647_2x2binned_10bpp[] = { + }; + + static struct regval_list ov5647_640x480_10bpp[] = { +- {0x0100, 0x00}, +- {0x0103, 0x01}, +- {0x3035, 0x11}, {0x3036, 0x46}, - {0x303c, 0x11}, +- {0x303c, 0x11}, - {0x3821, 0x07}, + {0x3821, 0x01}, {0x3820, 0x41}, - {0x370c, 0x03}, +- {0x370c, 0x03}, {0x3612, 0x59}, -@@ -509,7 +524,7 @@ static const struct ov5647_mode ov5647_modes[] = { + {0x3618, 0x00}, +- {0x5000, 0x06}, +- {0x5003, 0x08}, +- {0x5a00, 0x08}, +- {0x3000, 0xff}, +- {0x3001, 0xff}, +- {0x3002, 0xff}, +- {0x301d, 0xf0}, +- {0x3a18, 0x00}, +- {0x3a19, 0xf8}, +- {0x3c01, 0x80}, +- {0x3b07, 0x0c}, +- {0x380c, 0x07}, +- {0x380d, 0x3c}, + {0x3814, 0x35}, + {0x3815, 0x35}, + {0x3708, 0x64}, + {0x3709, 0x52}, +- {0x3808, 0x02}, +- {0x3809, 0x80}, +- {0x380a, 0x01}, +- {0x380b, 0xe0}, + {0x3800, 0x00}, + {0x3801, 0x10}, + {0x3802, 0x00}, +@@ -454,53 +355,17 @@ static struct regval_list ov5647_640x480_10bpp[] = { + {0x3805, 0x2f}, + {0x3806, 0x07}, + {0x3807, 0x9f}, +- {0x3630, 0x2e}, +- {0x3632, 0xe2}, +- {0x3633, 0x23}, +- {0x3634, 0x44}, +- {0x3620, 0x64}, +- {0x3621, 0xe0}, +- {0x3600, 0x37}, +- {0x3704, 0xa0}, +- {0x3703, 0x5a}, +- {0x3715, 0x78}, +- {0x3717, 0x01}, +- {0x3731, 0x02}, +- {0x370b, 0x60}, +- {0x3705, 0x1a}, +- {0x3f05, 0x02}, +- {0x3f06, 0x10}, +- {0x3f01, 0x0a}, +- {0x3a08, 0x01}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, + {0x3a09, 0x2e}, + {0x3a0a, 0x00}, + {0x3a0b, 0xfb}, + {0x3a0d, 0x02}, + {0x3a0e, 0x01}, +- {0x3a0f, 0x58}, +- {0x3a10, 0x50}, +- {0x3a1b, 0x58}, +- {0x3a1e, 0x50}, +- {0x3a11, 0x60}, +- {0x3a1f, 0x28}, +- {0x4001, 0x02}, + {0x4004, 0x02}, +- {0x4000, 0x09}, +- {0x3000, 0x00}, +- {0x3001, 0x00}, +- {0x3002, 0x00}, +- {0x3017, 0xe0}, +- {0x301c, 0xfc}, +- {0x3636, 0x06}, +- {0x3016, 0x08}, +- {0x3827, 0xec}, +- {0x3018, 0x44}, +- {0x3035, 0x21}, +- {0x3106, 0xf5}, +- {0x3034, 0x1a}, +- {0x301c, 0xf8}, + {0x4800, 0x34}, +- {0x3503, 0x03}, + {0x0100, 0x01}, + }; + +@@ -509,7 +374,7 @@ static const struct ov5647_mode ov5647_modes[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, @@ -119955,7 +126971,15 @@ index 8de398423b7c..3f89974963e0 100644 .field = V4L2_FIELD_NONE, .width = 2592, .height = 1944 -@@ -530,7 +545,7 @@ static const struct ov5647_mode ov5647_modes[] = { +@@ -521,6 +386,7 @@ static const struct ov5647_mode ov5647_modes[] = { + .height = 1944 + }, + .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 2844, + .vts = 0x7b0, + .reg_list = ov5647_2592x1944_10bpp, +@@ -530,7 +396,7 @@ static const struct ov5647_mode ov5647_modes[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, @@ -119964,7 +126988,17 @@ index 8de398423b7c..3f89974963e0 100644 .field = V4L2_FIELD_NONE, .width = 1920, .height = 1080 -@@ -551,7 +566,7 @@ static const struct ov5647_mode ov5647_modes[] = { +@@ -541,7 +407,8 @@ static const struct ov5647_mode ov5647_modes[] = { + .width = 1928, + .height = 1080, + }, +- .pixel_rate = 81666700, ++ .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 2416, + .vts = 0x450, + .reg_list = ov5647_1080p30_10bpp, +@@ -551,7 +418,7 @@ static const struct ov5647_mode ov5647_modes[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, @@ -119973,7 +127007,17 @@ index 8de398423b7c..3f89974963e0 100644 .field = V4L2_FIELD_NONE, .width = 1296, .height = 972 -@@ -572,7 +587,7 @@ static const struct ov5647_mode ov5647_modes[] = { +@@ -562,7 +429,8 @@ static const struct ov5647_mode ov5647_modes[] = { + .width = 2592, + .height = 1944, + }, +- .pixel_rate = 81666700, ++ .pixel_rate = 87500000, ++ .link_freq_index = FREQ_INDEX_FULL, + .hts = 1896, + .vts = 0x59b, + .reg_list = ov5647_2x2binned_10bpp, +@@ -572,7 +440,7 @@ static const struct ov5647_mode ov5647_modes[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, @@ -119982,7 +127026,15 @@ index 8de398423b7c..3f89974963e0 100644 .field = V4L2_FIELD_NONE, .width = 640, .height = 480 -@@ -602,7 +617,13 @@ static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val) +@@ -584,6 +452,7 @@ static const struct ov5647_mode ov5647_modes[] = { + .height = 1920, + }, + .pixel_rate = 55000000, ++ .link_freq_index = FREQ_INDEX_VGA, + .hts = 1852, + .vts = 0x1f8, + .reg_list = ov5647_640x480_10bpp, +@@ -602,7 +471,13 @@ static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val) int ret; ret = i2c_master_send(client, data, 4); @@ -119997,7 +127049,7 @@ index 8de398423b7c..3f89974963e0 100644 dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", __func__, reg); return ret; -@@ -618,10 +639,17 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) +@@ -618,10 +493,17 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) int ret; ret = i2c_master_send(client, data, 3); @@ -120017,7 +127069,21 @@ index 8de398423b7c..3f89974963e0 100644 } return 0; -@@ -778,6 +806,12 @@ static int ov5647_power_on(struct device *dev) +@@ -696,6 +578,13 @@ static int ov5647_set_mode(struct v4l2_subdev *sd) + if (ret < 0) + return ret; + ++ ret = ov5647_write_array(sd, ov5647_common_regs, ++ ARRAY_SIZE(ov5647_common_regs)); ++ if (ret < 0) { ++ dev_err(&client->dev, "write sensor common regs error\n"); ++ return ret; ++ } ++ + ret = ov5647_write_array(sd, sensor->mode->reg_list, + sensor->mode->num_regs); + if (ret < 0) { +@@ -778,6 +667,12 @@ static int ov5647_power_on(struct device *dev) dev_dbg(dev, "OV5647 power on\n"); @@ -120030,7 +127096,7 @@ index 8de398423b7c..3f89974963e0 100644 if (sensor->pwdn) { gpiod_set_value_cansleep(sensor->pwdn, 0); msleep(PWDN_ACTIVE_DELAY_MS); -@@ -809,6 +843,7 @@ static int ov5647_power_on(struct device *dev) +@@ -809,6 +704,7 @@ static int ov5647_power_on(struct device *dev) clk_disable_unprepare(sensor->xclk); error_pwdn: gpiod_set_value_cansleep(sensor->pwdn, 1); @@ -120038,7 +127104,7 @@ index 8de398423b7c..3f89974963e0 100644 return ret; } -@@ -838,6 +873,7 @@ static int ov5647_power_off(struct device *dev) +@@ -838,6 +734,7 @@ static int ov5647_power_off(struct device *dev) clk_disable_unprepare(sensor->xclk); gpiod_set_value_cansleep(sensor->pwdn, 1); @@ -120046,7 +127112,7 @@ index 8de398423b7c..3f89974963e0 100644 return 0; } -@@ -874,6 +910,8 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { +@@ -874,6 +771,8 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { .g_register = ov5647_sensor_get_register, .s_register = ov5647_sensor_set_register, #endif @@ -120055,7 +127121,7 @@ index 8de398423b7c..3f89974963e0 100644 }; static const struct v4l2_rect * -@@ -939,6 +977,25 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { +@@ -939,6 +838,25 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { .s_stream = ov5647_s_stream, }; @@ -120081,7 +127147,7 @@ index 8de398423b7c..3f89974963e0 100644 static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) -@@ -946,7 +1003,7 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, +@@ -946,7 +864,7 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; @@ -120090,7 +127156,7 @@ index 8de398423b7c..3f89974963e0 100644 return 0; } -@@ -957,7 +1014,7 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd, +@@ -957,7 +875,7 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd, { const struct v4l2_mbus_framefmt *fmt; @@ -120099,7 +127165,7 @@ index 8de398423b7c..3f89974963e0 100644 fse->index >= ARRAY_SIZE(ov5647_modes)) return -EINVAL; -@@ -990,6 +1047,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd, +@@ -990,6 +908,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd, } *fmt = *sensor_format; @@ -120108,8 +127174,22 @@ index 8de398423b7c..3f89974963e0 100644 mutex_unlock(&sensor->lock); return 0; -@@ -1037,6 +1096,8 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, +@@ -1020,7 +940,8 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, + mode->pixel_rate, 1, mode->pixel_rate); + + hblank = mode->hts - mode->format.width; +- __v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, ++ __v4l2_ctrl_modify_range(sensor->hblank, hblank, ++ OV5647_HTS_MAX - mode->format.width, 1, + hblank); + + vblank = mode->vts - mode->format.height; +@@ -1035,8 +956,12 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, + sensor->exposure->minimum, + exposure_max, sensor->exposure->step, exposure_def); ++ ++ __v4l2_ctrl_s_ctrl(sensor->link_freq, mode->link_freq_index); } *fmt = mode->format; + /* The code we pass back must reflect the current h/vflips. */ @@ -120117,7 +127197,7 @@ index 8de398423b7c..3f89974963e0 100644 mutex_unlock(&sensor->lock); return 0; -@@ -1212,6 +1273,25 @@ static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) +@@ -1212,6 +1137,25 @@ static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) return ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4); } @@ -120143,7 +127223,22 @@ index 8de398423b7c..3f89974963e0 100644 static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov5647 *sensor = container_of(ctrl->handler, -@@ -1274,6 +1354,14 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) +@@ -1263,6 +1207,10 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) + ret = ov5647_write16(sd, OV5647_REG_VTS_HI, + sensor->mode->format.height + ctrl->val); + break; ++ case V4L2_CID_HBLANK: ++ ret = ov5647_write16(sd, OV5647_REG_HTS_HI, ++ sensor->mode->format.width + ctrl->val); ++ break; + case V4L2_CID_TEST_PATTERN: + ret = ov5647_write(sd, OV5647_REG_ISPCTRL3D, + ov5647_test_pattern_val[ctrl->val]); +@@ -1270,10 +1218,17 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) + + /* Read-only, but we adjust it based on mode. */ + case V4L2_CID_PIXEL_RATE: +- case V4L2_CID_HBLANK: /* Read-only, but we adjust it based on mode. */ break; @@ -120158,7 +127253,7 @@ index 8de398423b7c..3f89974963e0 100644 default: dev_info(&client->dev, "Control (id:0x%x, val:0x%x) not supported\n", -@@ -1290,10 +1378,23 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = { +@@ -1290,12 +1245,25 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = { .s_ctrl = ov5647_s_ctrl, }; @@ -120181,9 +127276,26 @@ index 8de398423b7c..3f89974963e0 100644 int hblank, exposure_max, exposure_def; + struct v4l2_fwnode_device_properties props; - v4l2_ctrl_handler_init(&sensor->ctrls, 9); +- v4l2_ctrl_handler_init(&sensor->ctrls, 9); ++ v4l2_ctrl_handler_init(&sensor->ctrls, 10); -@@ -1344,6 +1445,21 @@ static int ov5647_init_controls(struct ov5647 *sensor) + v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 0); +@@ -1326,10 +1294,11 @@ static int ov5647_init_controls(struct ov5647 *sensor) + sensor->mode->pixel_rate, 1, + sensor->mode->pixel_rate); + +- /* By default, HBLANK is read only, but it does change per mode. */ + hblank = sensor->mode->hts - sensor->mode->format.width; + sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, +- V4L2_CID_HBLANK, hblank, hblank, 1, ++ V4L2_CID_HBLANK, hblank, ++ OV5647_HTS_MAX - ++ sensor->mode->format.width, 1, + hblank); + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, +@@ -1344,11 +1313,33 @@ static int ov5647_init_controls(struct ov5647 *sensor) ARRAY_SIZE(ov5647_test_pattern_menu) - 1, 0, 0, ov5647_test_pattern_menu); @@ -120197,6 +127309,14 @@ index 8de398423b7c..3f89974963e0 100644 + if (sensor->vflip) + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ++ sensor->link_freq = ++ v4l2_ctrl_new_int_menu(&sensor->ctrls, &ov5647_ctrl_ops, ++ V4L2_CID_LINK_FREQ, ++ ARRAY_SIZE(ov5647_link_freqs) - 1, 0, ++ ov5647_link_freqs); ++ if (sensor->link_freq) ++ sensor->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ + v4l2_fwnode_device_parse(dev, &props); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops, @@ -120205,7 +127325,12 @@ index 8de398423b7c..3f89974963e0 100644 if (sensor->ctrls.error) goto handler_free; -@@ -1426,11 +1542,17 @@ static int ov5647_probe(struct i2c_client *client) + sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; +- sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->sd.ctrl_handler = &sensor->ctrls; + + return 0; +@@ -1426,11 +1417,17 @@ static int ov5647_probe(struct i2c_client *client) return -EINVAL; } @@ -120224,7 +127349,7 @@ index 8de398423b7c..3f89974963e0 100644 if (ret) goto mutex_destroy; -@@ -1453,7 +1575,7 @@ static int ov5647_probe(struct i2c_client *client) +@@ -1453,7 +1450,7 @@ static int ov5647_probe(struct i2c_client *client) if (ret < 0) goto power_off; @@ -124370,6 +131495,8251 @@ index addb8f2d8939..ee5b77a1a2f3 100644 + media_request_put(req); +} +EXPORT_SYMBOL_GPL(media_request_unpin); +diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig +index ee095bde0b68..2a08336032da 100644 +--- a/drivers/media/pci/Kconfig ++++ b/drivers/media/pci/Kconfig +@@ -74,6 +74,7 @@ config VIDEO_PCI_SKELETON + when developing new drivers. + + source "drivers/media/pci/intel/Kconfig" ++source "drivers/media/pci/hailo/Kconfig" + + endif #MEDIA_PCI_SUPPORT + endif #PCI +diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile +index 8bed619b7130..54cfaa874841 100644 +--- a/drivers/media/pci/Makefile ++++ b/drivers/media/pci/Makefile +@@ -17,7 +17,8 @@ obj-y += ttpci/ \ + saa7146/ \ + smipcie/ \ + netup_unidvb/ \ +- intel/ ++ intel/ \ ++ hailo/ + + # Please keep it alphabetically sorted by Kconfig name + # (e. g. LC_ALL=C sort Makefile) +diff --git a/drivers/media/pci/hailo/Kconfig b/drivers/media/pci/hailo/Kconfig +new file mode 100644 +index 000000000000..bd011b6b8f0e +--- /dev/null ++++ b/drivers/media/pci/hailo/Kconfig +@@ -0,0 +1,6 @@ ++ ++config MEDIA_PCI_HAILO ++ tristate "Hailo AI accelerator PCIe driver" ++ depends on PCI ++ help ++ Enable build of Hailo AI accelerator PCIe driver. +diff --git a/drivers/media/pci/hailo/Makefile b/drivers/media/pci/hailo/Makefile +new file mode 100644 +index 000000000000..cea09ca1ee37 +--- /dev/null ++++ b/drivers/media/pci/hailo/Makefile +@@ -0,0 +1,34 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++COMMON_SRC_DIRECTORY=common ++VDMA_SRC_DIRECTORY=vdma ++UTILS_SRC_DIRECTORY=utils ++ ++obj-$(CONFIG_MEDIA_PCI_HAILO) := hailo_pci.o ++ ++hailo_pci-objs += src/pcie.o ++hailo_pci-objs += src/fops.o ++hailo_pci-objs += src/utils.o ++hailo_pci-objs += src/sysfs.o ++hailo_pci-objs += src/pci_soc_ioctl.o ++ ++hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/fw_validation.o ++hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/fw_operation.o ++hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/pcie_common.o ++hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/vdma_common.o ++hailo_pci-objs += $(COMMON_SRC_DIRECTORY)/hailo_resource.o ++ ++hailo_pci-objs += $(UTILS_SRC_DIRECTORY)/logs.o ++hailo_pci-objs += $(UTILS_SRC_DIRECTORY)/integrated_nnc_utils.o ++ ++hailo_pci-objs += $(VDMA_SRC_DIRECTORY)/vdma.o ++hailo_pci-objs += $(VDMA_SRC_DIRECTORY)/memory.o ++hailo_pci-objs += $(VDMA_SRC_DIRECTORY)/ioctl.o ++ ++ccflags-y += -Werror ++ccflags-y += -DHAILO_RASBERRY_PIE ++ccflags-y += -I$(srctree)/$(src) ++ccflags-y += -I$(srctree)/$(src)/include ++ccflags-y += -I$(srctree)/$(src)/common ++ ++clean-files := $(hailo_pci-objs) +diff --git a/drivers/media/pci/hailo/common/fw_operation.c b/drivers/media/pci/hailo/common/fw_operation.c +new file mode 100644 +index 000000000000..ef9926441981 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/fw_operation.c +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. ++**/ ++ ++#include "fw_operation.h" ++ ++#include ++#include ++#include ++#include ++ ++typedef struct { ++ u32 host_offset; ++ u32 chip_offset; ++} FW_DEBUG_BUFFER_HEADER_t; ++ ++#define DEBUG_BUFFER_DATA_SIZE (DEBUG_BUFFER_TOTAL_SIZE - sizeof(FW_DEBUG_BUFFER_HEADER_t)) ++ ++int hailo_read_firmware_notification(struct hailo_resource *resource, struct hailo_d2h_notification *notification) ++{ ++ hailo_d2h_buffer_details_t d2h_buffer_details = {0, 0}; ++ hailo_resource_read_buffer(resource, 0, sizeof(d2h_buffer_details), ++ &d2h_buffer_details); ++ ++ if ((sizeof(notification->buffer) < d2h_buffer_details.buffer_len) || (0 == d2h_buffer_details.is_buffer_in_use)) { ++ return -EINVAL; ++ } ++ ++ notification->buffer_len = d2h_buffer_details.buffer_len; ++ hailo_resource_read_buffer(resource, sizeof(d2h_buffer_details), notification->buffer_len, notification->buffer); ++ ++ // Write is_buffer_in_use = false ++ hailo_resource_write16(resource, 0, 0); ++ return 0; ++} ++ ++static inline size_t calculate_log_ready_to_read(FW_DEBUG_BUFFER_HEADER_t *header) ++{ ++ size_t ready_to_read = 0; ++ size_t host_offset = header->host_offset; ++ size_t chip_offset = header->chip_offset; ++ ++ if (chip_offset >= host_offset) { ++ ready_to_read = chip_offset - host_offset; ++ } else { ++ ready_to_read = DEBUG_BUFFER_DATA_SIZE - (host_offset - chip_offset); ++ } ++ ++ return ready_to_read; ++} ++ ++long hailo_read_firmware_log(struct hailo_resource *fw_logger_resource, struct hailo_read_log_params *params) ++{ ++ FW_DEBUG_BUFFER_HEADER_t debug_buffer_header = {0}; ++ size_t read_offset = 0; ++ size_t ready_to_read = 0; ++ size_t size_to_read = 0; ++ uintptr_t user_buffer = (uintptr_t)params->buffer; ++ ++ if (params->buffer_size > ARRAY_SIZE(params->buffer)) { ++ return -EINVAL; ++ } ++ ++ hailo_resource_read_buffer(fw_logger_resource, 0, sizeof(debug_buffer_header), ++ &debug_buffer_header); ++ ++ /* Point to the start of the data buffer. */ ++ ready_to_read = calculate_log_ready_to_read(&debug_buffer_header); ++ if (0 == ready_to_read) { ++ params->read_bytes = 0; ++ return 0; ++ } ++ /* If ready to read is bigger than the buffer size, read only buffer size bytes. */ ++ ready_to_read = min(ready_to_read, params->buffer_size); ++ ++ /* Point to the data that is read to be read by the host. */ ++ read_offset = sizeof(debug_buffer_header) + debug_buffer_header.host_offset; ++ /* Check if the offset should cycle back to beginning. */ ++ if (DEBUG_BUFFER_DATA_SIZE <= debug_buffer_header.host_offset + ready_to_read) { ++ size_to_read = DEBUG_BUFFER_DATA_SIZE - debug_buffer_header.host_offset; ++ hailo_resource_read_buffer(fw_logger_resource, read_offset, size_to_read, (void*)user_buffer); ++ ++ user_buffer += size_to_read; ++ size_to_read = ready_to_read - size_to_read; ++ /* Point back to the beginning of the data buffer. */ ++ read_offset -= debug_buffer_header.host_offset; ++ } ++ else { ++ size_to_read = ready_to_read; ++ } ++ ++ /* size_to_read may become 0 if the read reached DEBUG_BUFFER_DATA_SIZE exactly */ ++ hailo_resource_read_buffer(fw_logger_resource, read_offset, size_to_read, (void*)user_buffer); ++ ++ /* Change current_offset to represent the new host offset. */ ++ read_offset += size_to_read; ++ hailo_resource_write32(fw_logger_resource, offsetof(FW_DEBUG_BUFFER_HEADER_t, host_offset), ++ (u32)(read_offset - sizeof(debug_buffer_header))); ++ ++ params->read_bytes = ready_to_read; ++ return 0; ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/fw_operation.h b/drivers/media/pci/hailo/common/fw_operation.h +new file mode 100644 +index 000000000000..c7cf068bdb3f +--- /dev/null ++++ b/drivers/media/pci/hailo/common/fw_operation.h +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. ++**/ ++ ++#ifndef _HAILO_COMMON_FIRMWARE_OPERATION_H_ ++#define _HAILO_COMMON_FIRMWARE_OPERATION_H_ ++ ++#include "hailo_resource.h" ++ ++#define DEBUG_BUFFER_TOTAL_SIZE (4*1024) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int hailo_read_firmware_notification(struct hailo_resource *resource, struct hailo_d2h_notification *notification); ++ ++long hailo_read_firmware_log(struct hailo_resource *fw_logger_resource, struct hailo_read_log_params *params); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _HAILO_COMMON_FIRMWARE_OPERATION_H_ */ +diff --git a/drivers/media/pci/hailo/common/fw_validation.c b/drivers/media/pci/hailo/common/fw_validation.c +new file mode 100644 +index 000000000000..a197435c102d +--- /dev/null ++++ b/drivers/media/pci/hailo/common/fw_validation.c +@@ -0,0 +1,114 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "fw_validation.h" ++#include ++#include ++ ++ ++ ++/* when reading the firmware we don't want to read past the firmware_size, ++ so we have a consumed_firmware_offset that is updated _before_ accessing data at that offset ++ of firmware_base_address */ ++#define CONSUME_FIRMWARE(__size, __err) do { \ ++ consumed_firmware_offset += (u32) (__size); \ ++ if ((firmware_size < (__size)) || (firmware_size < consumed_firmware_offset)) { \ ++ err = __err; \ ++ goto exit; \ ++ } \ ++ } while(0) ++ ++int FW_VALIDATION__validate_fw_header(uintptr_t firmware_base_address, ++ size_t firmware_size, u32 max_code_size, u32 *outer_consumed_firmware_offset, ++ firmware_header_t **out_firmware_header, enum hailo_board_type board_type) ++{ ++ int err = -EINVAL; ++ firmware_header_t *firmware_header = NULL; ++ u32 consumed_firmware_offset = *outer_consumed_firmware_offset; ++ u32 expected_firmware_magic = 0; ++ ++ firmware_header = (firmware_header_t *) (firmware_base_address + consumed_firmware_offset); ++ CONSUME_FIRMWARE(sizeof(firmware_header_t), -EINVAL); ++ ++ switch (board_type) { ++ case HAILO_BOARD_TYPE_HAILO8: ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO8; ++ break; ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: ++ case HAILO_BOARD_TYPE_HAILO15: ++ case HAILO_BOARD_TYPE_HAILO10H: ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15; ++ break; ++ case HAILO_BOARD_TYPE_PLUTO: ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_PLUTO; ++ break; ++ default: ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if (expected_firmware_magic != firmware_header->magic) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* Validate that the firmware header version is supported */ ++ switch(firmware_header->header_version) { ++ case FIRMWARE_HEADER_VERSION_INITIAL: ++ break; ++ default: ++ err = -EINVAL; ++ goto exit; ++ break; ++ } ++ ++ if (MINIMUM_FIRMWARE_CODE_SIZE > firmware_header->code_size) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if (max_code_size < firmware_header->code_size) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ CONSUME_FIRMWARE(firmware_header->code_size, -EINVAL); ++ ++ *outer_consumed_firmware_offset = consumed_firmware_offset; ++ *out_firmware_header = firmware_header; ++ err = 0; ++ ++exit: ++ return err; ++} ++ ++int FW_VALIDATION__validate_cert_header(uintptr_t firmware_base_address, ++ size_t firmware_size, u32 *outer_consumed_firmware_offset, secure_boot_certificate_t **out_firmware_cert) ++{ ++ ++ secure_boot_certificate_t *firmware_cert = NULL; ++ int err = -EINVAL; ++ u32 consumed_firmware_offset = *outer_consumed_firmware_offset; ++ ++ firmware_cert = (secure_boot_certificate_t *) (firmware_base_address + consumed_firmware_offset); ++ CONSUME_FIRMWARE(sizeof(secure_boot_certificate_t), -EINVAL); ++ ++ if ((MAXIMUM_FIRMWARE_CERT_KEY_SIZE < firmware_cert->key_size) || ++ (MAXIMUM_FIRMWARE_CERT_CONTENT_SIZE < firmware_cert->content_size)) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ CONSUME_FIRMWARE(firmware_cert->key_size, -EINVAL); ++ CONSUME_FIRMWARE(firmware_cert->content_size, -EINVAL); ++ ++ *outer_consumed_firmware_offset = consumed_firmware_offset; ++ *out_firmware_cert = firmware_cert; ++ err = 0; ++ ++exit: ++ return err; ++} ++ +diff --git a/drivers/media/pci/hailo/common/fw_validation.h b/drivers/media/pci/hailo/common/fw_validation.h +new file mode 100644 +index 000000000000..106ee5007297 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/fw_validation.h +@@ -0,0 +1,65 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef PCIE_COMMON_FIRMWARE_HEADER_UTILS_H_ ++#define PCIE_COMMON_FIRMWARE_HEADER_UTILS_H_ ++ ++#include "hailo_ioctl_common.h" ++#include ++ ++#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0) ++#define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB) ++#define FIRMWARE_HEADER_MAGIC_PLUTO (0xF94739AB) ++ ++#ifndef HAILO_EMULATOR ++#define FIRMWARE_WAIT_TIMEOUT_MS (5000) ++#else /* ifndef HAILO_EMULATOR */ ++#define FIRMWARE_WAIT_TIMEOUT_MS (500000) ++#endif /* ifndef HAILO_EMULATOR */ ++ ++typedef enum { ++ FIRMWARE_HEADER_VERSION_INITIAL = 0, ++ ++ /* MUST BE LAST */ ++ FIRMWARE_HEADER_VERSION_COUNT ++} firmware_header_version_t; ++ ++typedef struct { ++ u32 magic; ++ u32 header_version; ++ u32 firmware_major; ++ u32 firmware_minor; ++ u32 firmware_revision; ++ u32 code_size; ++} firmware_header_t; ++ ++ ++#ifdef _MSC_VER ++#pragma warning(push) ++#pragma warning(disable:4200) ++#endif /* _MSC_VER */ ++ ++typedef struct { ++ u32 key_size; ++ u32 content_size; ++ u8 certificates_data[0]; ++} secure_boot_certificate_t; ++ ++#ifdef _MSC_VER ++#pragma warning(pop) ++#endif /* _MSC_VER */ ++ ++#define MINIMUM_FIRMWARE_CODE_SIZE (20*4) ++#define MAXIMUM_FIRMWARE_CERT_KEY_SIZE (0x1000) ++#define MAXIMUM_FIRMWARE_CERT_CONTENT_SIZE (0x1000) ++ ++int FW_VALIDATION__validate_fw_header(uintptr_t firmware_base_address, ++ size_t firmware_size, u32 max_code_size, u32 *outer_consumed_firmware_offset, ++ firmware_header_t **out_firmware_header, enum hailo_board_type board_type); ++ ++int FW_VALIDATION__validate_cert_header(uintptr_t firmware_base_address, ++ size_t firmware_size, u32 *outer_consumed_firmware_offset, secure_boot_certificate_t **out_firmware_cert); ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/hailo_ioctl_common.h b/drivers/media/pci/hailo/common/hailo_ioctl_common.h +new file mode 100644 +index 000000000000..5f6cddf5aa2e +--- /dev/null ++++ b/drivers/media/pci/hailo/common/hailo_ioctl_common.h +@@ -0,0 +1,669 @@ ++// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_IOCTL_COMMON_H_ ++#define _HAILO_IOCTL_COMMON_H_ ++ ++#define HAILO_DRV_VER_MAJOR 4 ++#define HAILO_DRV_VER_MINOR 18 ++#define HAILO_DRV_VER_REVISION 0 ++ ++#define _STRINGIFY_EXPANDED( x ) #x ++#define _STRINGIFY_NUMBER( x ) _STRINGIFY_EXPANDED(x) ++#define HAILO_DRV_VER _STRINGIFY_NUMBER(HAILO_DRV_VER_MAJOR) "." _STRINGIFY_NUMBER(HAILO_DRV_VER_MINOR) "." _STRINGIFY_NUMBER(HAILO_DRV_VER_REVISION) ++ ++ ++// This value is not easily changeable. ++// For example: the channel interrupts ioctls assume we have up to 32 channels ++#define MAX_VDMA_CHANNELS_PER_ENGINE (32) ++#define MAX_VDMA_ENGINES (3) ++#define SIZE_OF_VDMA_DESCRIPTOR (16) ++#define VDMA_DEST_CHANNELS_START (16) ++ ++#define HAILO_VDMA_MAX_ONGOING_TRANSFERS (128) ++#define HAILO_VDMA_MAX_ONGOING_TRANSFERS_MASK (HAILO_VDMA_MAX_ONGOING_TRANSFERS - 1) ++ ++#define CHANNEL_IRQ_TIMESTAMPS_SIZE (HAILO_VDMA_MAX_ONGOING_TRANSFERS * 2) ++#define CHANNEL_IRQ_TIMESTAMPS_SIZE_MASK (CHANNEL_IRQ_TIMESTAMPS_SIZE - 1) ++ ++#define INVALID_DRIVER_HANDLE_VALUE ((uintptr_t)-1) ++ ++// Used by windows and unix driver to raise the right CPU control handle to the FW. The same as in pcie_service FW ++#define FW_ACCESS_CORE_CPU_CONTROL_SHIFT (1) ++#define FW_ACCESS_CORE_CPU_CONTROL_MASK (1 << FW_ACCESS_CORE_CPU_CONTROL_SHIFT) ++#define FW_ACCESS_CONTROL_INTERRUPT_SHIFT (0) ++#define FW_ACCESS_APP_CPU_CONTROL_MASK (1 << FW_ACCESS_CONTROL_INTERRUPT_SHIFT) ++#define FW_ACCESS_DRIVER_SHUTDOWN_SHIFT (2) ++#define FW_ACCESS_DRIVER_SHUTDOWN_MASK (1 << FW_ACCESS_DRIVER_SHUTDOWN_SHIFT) ++#define FW_ACCESS_SOC_CONNECT_SHIFT (3) ++#define FW_ACCESS_SOC_CONNECT_MASK (1 << FW_ACCESS_SOC_CONNECT_SHIFT) ++ ++#define INVALID_VDMA_CHANNEL (0xff) ++ ++ ++#if !defined(__cplusplus) && defined(NTDDI_VERSION) ++#include ++typedef ULONG uint32_t; ++typedef UCHAR uint8_t; ++typedef USHORT uint16_t; ++typedef ULONGLONG uint64_t; ++#endif /* !defined(__cplusplus) && defined(NTDDI_VERSION) */ ++ ++ ++#ifdef _MSC_VER ++ ++#include ++ ++#if !defined(bool) && !defined(__cplusplus) ++typedef uint8_t bool; ++#endif // !defined(bool) && !defined(__cplusplus) ++ ++#if !defined(INT_MAX) ++#define INT_MAX 0x7FFFFFFF ++#endif // !defined(INT_MAX) ++ ++#if !defined(ECONNRESET) ++#define ECONNRESET 104 /* Connection reset by peer */ ++#endif // !defined(ECONNRESET) ++ ++// {d88d31f1-fede-4e71-ac2a-6ce0018c1501} ++DEFINE_GUID (GUID_DEVINTERFACE_HailoKM_NNC, ++ 0xd88d31f1,0xfede,0x4e71,0xac,0x2a,0x6c,0xe0,0x01,0x8c,0x15,0x01); ++ ++// {7f16047d-64b8-207a-0092-e970893970a2} ++DEFINE_GUID (GUID_DEVINTERFACE_HailoKM_SOC, ++ 0x7f16047d,0x64b8,0x207a,0x00,0x92,0xe9,0x70,0x89,0x39,0x70,0xa2); ++ ++#define HAILO_GENERAL_IOCTL_MAGIC 0 ++#define HAILO_VDMA_IOCTL_MAGIC 1 ++#define HAILO_SOC_IOCTL_MAGIC 2 ++#define HAILO_PCI_EP_IOCTL_MAGIC 3 ++#define HAILO_NNC_IOCTL_MAGIC 4 ++ ++#define HAILO_IOCTL_COMPATIBLE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) ++ ++ ++typedef struct tCompatibleHailoIoctlParam ++{ ++ union { ++ struct { ++ ULONG Size : 16; ++ ULONG Code : 8; ++ ULONG Type : 6; ++ ULONG Read : 1; ++ ULONG Write : 1; ++ } bits; ++ ULONG value; ++ } u; ++} tCompatibleHailoIoctlParam; ++ ++static ULONG FORCEINLINE _IOC_(ULONG nr, ULONG type, ULONG size, bool read, bool write) ++{ ++ struct tCompatibleHailoIoctlParam param; ++ param.u.bits.Code = nr; ++ param.u.bits.Size = size; ++ param.u.bits.Type = type; ++ param.u.bits.Read = read ? 1 : 0; ++ param.u.bits.Write = write ? 1 : 0; ++ return param.u.value; ++} ++ ++#define _IOW_(type,nr,size) _IOC_(nr, type, sizeof(size), true, false) ++#define _IOR_(type,nr,size) _IOC_(nr, type, sizeof(size), false, true) ++#define _IOWR_(type,nr,size) _IOC_(nr, type, sizeof(size), true, true) ++#define _IO_(type,nr) _IOC_(nr, type, 0, false, false) ++ ++#elif defined(__linux__) // #ifdef _MSC_VER ++#ifndef __KERNEL__ ++// include the userspace headers only if this file is included by user space program ++// It is discourged to include them when compiling the driver (https://lwn.net/Articles/113349/) ++#include ++#include ++#else ++#include ++#include ++#include ++#endif // ifndef __KERNEL__ ++ ++#include ++ ++#define _IOW_ _IOW ++#define _IOR_ _IOR ++#define _IOWR_ _IOWR ++#define _IO_ _IO ++ ++#define HAILO_GENERAL_IOCTL_MAGIC 'g' ++#define HAILO_VDMA_IOCTL_MAGIC 'v' ++#define HAILO_SOC_IOCTL_MAGIC 's' ++#define HAILO_NNC_IOCTL_MAGIC 'n' ++#define HAILO_PCI_EP_IOCTL_MAGIC 'p' ++ ++#elif defined(__QNX__) // #ifdef _MSC_VER ++#include ++#include ++#include ++#include ++#include ++ ++// defines for devctl ++#define _IOW_ __DIOF ++#define _IOR_ __DIOT ++#define _IOWR_ __DIOTF ++#define _IO_ __DION ++#define HAILO_GENERAL_IOCTL_MAGIC _DCMD_ALL ++#define HAILO_VDMA_IOCTL_MAGIC _DCMD_MISC ++ ++#else // #ifdef _MSC_VER ++#error "unsupported platform!" ++#endif ++ ++#pragma pack(push, 1) ++ ++struct hailo_channel_interrupt_timestamp { ++ uint64_t timestamp_ns; ++ uint16_t desc_num_processed; ++}; ++ ++typedef struct { ++ uint16_t is_buffer_in_use; ++ uint16_t buffer_len; ++} hailo_d2h_buffer_details_t; ++ ++// This struct is the same as `enum dma_data_direction` (defined in linux/dma-direction) ++enum hailo_dma_data_direction { ++ HAILO_DMA_BIDIRECTIONAL = 0, ++ HAILO_DMA_TO_DEVICE = 1, ++ HAILO_DMA_FROM_DEVICE = 2, ++ HAILO_DMA_NONE = 3, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_DMA_MAX_ENUM = INT_MAX, ++}; ++ ++// Enum that states what type of buffer we are working with in the driver ++// TODO: HRT-13580 - Add specific type for user allocated and for driver allocated ++enum hailo_dma_buffer_type { ++ HAILO_DMA_USER_PTR_BUFFER = 0, ++ HAILO_DMA_DMABUF_BUFFER = 1, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_DMA_BUFFER_MAX_ENUM = INT_MAX, ++}; ++ ++// Enum that determines if buffer should be allocated from user space or from driver ++enum hailo_allocation_mode { ++ HAILO_ALLOCATION_MODE_USERSPACE = 0, ++ HAILO_ALLOCATION_MODE_DRIVER = 1, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_ALLOCATION_MODE_MAX_ENUM = INT_MAX, ++}; ++ ++enum hailo_vdma_interrupts_domain { ++ HAILO_VDMA_INTERRUPTS_DOMAIN_NONE = 0, ++ HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE = (1 << 0), ++ HAILO_VDMA_INTERRUPTS_DOMAIN_HOST = (1 << 1), ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_VDMA_INTERRUPTS_DOMAIN_MAX_ENUM = INT_MAX, ++}; ++ ++/* structure used in ioctl HAILO_VDMA_BUFFER_MAP */ ++struct hailo_vdma_buffer_map_params { ++#if defined(__linux__) || defined(_MSC_VER) ++ uintptr_t user_address; // in ++#elif defined(__QNX__) ++ shm_handle_t shared_memory_handle; // in ++#else ++#error "unsupported platform!" ++#endif // __linux__ ++ size_t size; // in ++ enum hailo_dma_data_direction data_direction; // in ++ enum hailo_dma_buffer_type buffer_type; // in ++ uintptr_t allocated_buffer_handle; // in ++ size_t mapped_handle; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_BUFFER_UNMAP */ ++struct hailo_vdma_buffer_unmap_params { ++ size_t mapped_handle; ++}; ++ ++/* structure used in ioctl HAILO_DESC_LIST_CREATE */ ++struct hailo_desc_list_create_params { ++ size_t desc_count; // in ++ uint16_t desc_page_size; // in ++ bool is_circular; // in ++ uintptr_t desc_handle; // out ++ uint64_t dma_address; // out ++}; ++ ++/* structure used in ioctl HAILO_DESC_LIST_RELEASE */ ++struct hailo_desc_list_release_params { ++ uintptr_t desc_handle; // in ++}; ++ ++/* structure used in ioctl HAILO_DESC_LIST_BIND_VDMA_BUFFER */ ++struct hailo_desc_list_program_params { ++ size_t buffer_handle; // in ++ size_t buffer_size; // in ++ size_t buffer_offset; // in ++ uintptr_t desc_handle; // in ++ uint8_t channel_index; // in ++ uint32_t starting_desc; // in ++ bool should_bind; // in ++ enum hailo_vdma_interrupts_domain last_interrupts_domain; // in ++ bool is_debug; // in ++}; ++ ++/* structure used in ioctl HAILO_VDMA_ENABLE_CHANNELS */ ++struct hailo_vdma_enable_channels_params { ++ uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES]; // in ++ bool enable_timestamps_measure; // in ++}; ++ ++/* structure used in ioctl HAILO_VDMA_DISABLE_CHANNELS */ ++struct hailo_vdma_disable_channels_params { ++ uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES]; // in ++}; ++ ++/* structure used in ioctl HAILO_VDMA_INTERRUPTS_WAIT */ ++struct hailo_vdma_interrupts_channel_data { ++ uint8_t engine_index; ++ uint8_t channel_index; ++ bool is_active; // If not activate, num_processed is ignored. ++ uint8_t transfers_completed; // Number of transfers completed. ++ uint8_t host_error; // Channel errors bits on source side ++ uint8_t device_error; // Channel errors bits on dest side ++ bool validation_success; // If the validation of the channel was successful ++}; ++ ++struct hailo_vdma_interrupts_wait_params { ++ uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES]; // in ++ uint8_t channels_count; // out ++ struct hailo_vdma_interrupts_channel_data ++ irq_data[MAX_VDMA_CHANNELS_PER_ENGINE * MAX_VDMA_ENGINES]; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS */ ++struct hailo_vdma_interrupts_read_timestamp_params { ++ uint8_t engine_index; // in ++ uint8_t channel_index; // in ++ uint32_t timestamps_count; // out ++ struct hailo_channel_interrupt_timestamp timestamps[CHANNEL_IRQ_TIMESTAMPS_SIZE]; // out ++}; ++ ++/* structure used in ioctl HAILO_FW_CONTROL */ ++#define MAX_CONTROL_LENGTH (1500) ++#define PCIE_EXPECTED_MD5_LENGTH (16) ++ ++ ++/* structure used in ioctl HAILO_FW_CONTROL and HAILO_READ_LOG */ ++enum hailo_cpu_id { ++ HAILO_CPU_ID_CPU0 = 0, ++ HAILO_CPU_ID_CPU1, ++ HAILO_CPU_ID_NONE, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_CPU_MAX_ENUM = INT_MAX, ++}; ++ ++struct hailo_fw_control { ++ // expected_md5+buffer_len+buffer must be in this order at the start of the struct ++ uint8_t expected_md5[PCIE_EXPECTED_MD5_LENGTH]; ++ uint32_t buffer_len; ++ uint8_t buffer[MAX_CONTROL_LENGTH]; ++ uint32_t timeout_ms; ++ enum hailo_cpu_id cpu_id; ++}; ++ ++/* structure used in ioctl HAILO_MEMORY_TRANSFER */ ++// Max bar transfer size gotten from ATR0_TABLE_SIZE ++#define MAX_MEMORY_TRANSFER_LENGTH (4096) ++ ++enum hailo_transfer_direction { ++ TRANSFER_READ = 0, ++ TRANSFER_WRITE, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ TRANSFER_MAX_ENUM = INT_MAX, ++}; ++ ++enum hailo_transfer_memory_type { ++ HAILO_TRANSFER_DEVICE_DIRECT_MEMORY, ++ ++ // vDMA memories ++ HAILO_TRANSFER_MEMORY_VDMA0 = 0x100, ++ HAILO_TRANSFER_MEMORY_VDMA1, ++ HAILO_TRANSFER_MEMORY_VDMA2, ++ ++ // PCIe driver memories ++ HAILO_TRANSFER_MEMORY_PCIE_BAR0 = 0x200, ++ HAILO_TRANSFER_MEMORY_PCIE_BAR2 = 0x202, ++ HAILO_TRANSFER_MEMORY_PCIE_BAR4 = 0x204, ++ ++ // DRAM DMA driver memories ++ HAILO_TRANSFER_MEMORY_DMA_ENGINE0 = 0x300, ++ HAILO_TRANSFER_MEMORY_DMA_ENGINE1, ++ HAILO_TRANSFER_MEMORY_DMA_ENGINE2, ++ ++ // PCIe EP driver memories ++ HAILO_TRANSFER_MEMORY_PCIE_EP_CONFIG = 0x400, ++ HAILO_TRANSFER_MEMORY_PCIE_EP_BRIDGE, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_TRANSFER_MEMORY_MAX_ENUM = INT_MAX, ++}; ++ ++struct hailo_memory_transfer_params { ++ enum hailo_transfer_direction transfer_direction; // in ++ enum hailo_transfer_memory_type memory_type; // in ++ uint64_t address; // in ++ size_t count; // in ++ uint8_t buffer[MAX_MEMORY_TRANSFER_LENGTH]; // in/out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_BUFFER_SYNC */ ++enum hailo_vdma_buffer_sync_type { ++ HAILO_SYNC_FOR_CPU, ++ HAILO_SYNC_FOR_DEVICE, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_SYNC_MAX_ENUM = INT_MAX, ++}; ++ ++struct hailo_vdma_buffer_sync_params { ++ size_t handle; // in ++ enum hailo_vdma_buffer_sync_type sync_type; // in ++ size_t offset; // in ++ size_t count; // in ++}; ++ ++/* structure used in ioctl HAILO_READ_NOTIFICATION */ ++#define MAX_NOTIFICATION_LENGTH (1500) ++ ++struct hailo_d2h_notification { ++ size_t buffer_len; // out ++ uint8_t buffer[MAX_NOTIFICATION_LENGTH]; // out ++}; ++ ++enum hailo_board_type { ++ HAILO_BOARD_TYPE_HAILO8 = 0, ++ HAILO_BOARD_TYPE_HAILO15, ++ HAILO_BOARD_TYPE_PLUTO, ++ HAILO_BOARD_TYPE_HAILO10H, ++ HAILO_BOARD_TYPE_HAILO10H_LEGACY, ++ HAILO_BOARD_TYPE_COUNT, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_BOARD_TYPE_MAX_ENUM = INT_MAX ++}; ++ ++enum hailo_accelerator_type { ++ HAILO_ACCELERATOR_TYPE_NNC, ++ HAILO_ACCELERATOR_TYPE_SOC, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_ACCELERATOR_TYPE_MAX_ENUM = INT_MAX ++}; ++ ++enum hailo_dma_type { ++ HAILO_DMA_TYPE_PCIE, ++ HAILO_DMA_TYPE_DRAM, ++ HAILO_DMA_TYPE_PCI_EP, ++ ++ /** Max enum value to maintain ABI Integrity */ ++ HAILO_DMA_TYPE_MAX_ENUM = INT_MAX, ++}; ++ ++struct hailo_device_properties { ++ uint16_t desc_max_page_size; ++ enum hailo_board_type board_type; ++ enum hailo_allocation_mode allocation_mode; ++ enum hailo_dma_type dma_type; ++ size_t dma_engines_count; ++ bool is_fw_loaded; ++#ifdef __QNX__ ++ pid_t resource_manager_pid; ++#endif // __QNX__ ++}; ++ ++struct hailo_driver_info { ++ uint32_t major_version; ++ uint32_t minor_version; ++ uint32_t revision_version; ++}; ++ ++/* structure used in ioctl HAILO_READ_LOG */ ++#define MAX_FW_LOG_BUFFER_LENGTH (512) ++ ++struct hailo_read_log_params { ++ enum hailo_cpu_id cpu_id; // in ++ uint8_t buffer[MAX_FW_LOG_BUFFER_LENGTH]; // out ++ size_t buffer_size; // in ++ size_t read_bytes; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC */ ++struct hailo_allocate_low_memory_buffer_params { ++ size_t buffer_size; // in ++ uintptr_t buffer_handle; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_LOW_MEMORY_BUFFER_FREE */ ++struct hailo_free_low_memory_buffer_params { ++ uintptr_t buffer_handle; // in ++}; ++ ++struct hailo_mark_as_in_use_params { ++ bool in_use; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC */ ++struct hailo_allocate_continuous_buffer_params { ++ size_t buffer_size; // in ++ uintptr_t buffer_handle; // out ++ uint64_t dma_address; // out ++}; ++ ++/* structure used in ioctl HAILO_VDMA_CONTINUOUS_BUFFER_FREE */ ++struct hailo_free_continuous_buffer_params { ++ uintptr_t buffer_handle; // in ++}; ++ ++/* structures used in ioctl HAILO_VDMA_LAUNCH_TRANSFER */ ++struct hailo_vdma_transfer_buffer { ++ size_t mapped_buffer_handle; // in ++ uint32_t offset; // in ++ uint32_t size; // in ++}; ++ ++// We allow maximum 2 buffers per transfer since we may have an extra buffer ++// to make sure each buffer is aligned to page size. ++#define HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER (2) ++ ++struct hailo_vdma_launch_transfer_params { ++ uint8_t engine_index; // in ++ uint8_t channel_index; // in ++ ++ uintptr_t desc_handle; // in ++ uint32_t starting_desc; // in ++ ++ bool should_bind; // in, if false, assumes buffer already bound. ++ uint8_t buffers_count; // in ++ struct hailo_vdma_transfer_buffer ++ buffers[HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER]; // in ++ ++ enum hailo_vdma_interrupts_domain first_interrupts_domain; // in ++ enum hailo_vdma_interrupts_domain last_interrupts_domain; // in ++ ++ bool is_debug; // in, if set program hw to send ++ // more info (e.g desc complete status) ++ ++ uint32_t descs_programed; // out, amount of descriptors programed. ++ int launch_transfer_status; // out, status of the launch transfer call. (only used in case of error) ++}; ++ ++/* structure used in ioctl HAILO_SOC_CONNECT */ ++struct hailo_soc_connect_params { ++ uint8_t input_channel_index; // out ++ uint8_t output_channel_index; // out ++ uintptr_t input_desc_handle; // in ++ uintptr_t output_desc_handle; // in ++}; ++ ++/* structure used in ioctl HAILO_SOC_CLOSE */ ++struct hailo_soc_close_params { ++ uint8_t input_channel_index; // in ++ uint8_t output_channel_index; // in ++}; ++ ++/* structure used in ioctl HAILO_PCI_EP_ACCEPT */ ++struct hailo_pci_ep_accept_params { ++ uint8_t input_channel_index; // out ++ uint8_t output_channel_index; // out ++ uintptr_t input_desc_handle; // in ++ uintptr_t output_desc_handle; // in ++}; ++ ++/* structure used in ioctl HAILO_PCI_EP_CLOSE */ ++struct hailo_pci_ep_close_params { ++ uint8_t input_channel_index; // in ++ uint8_t output_channel_index; // in ++}; ++ ++#ifdef _MSC_VER ++struct tCompatibleHailoIoctlData ++{ ++ tCompatibleHailoIoctlParam Parameters; ++ ULONG_PTR Value; ++ union { ++ struct hailo_memory_transfer_params MemoryTransfer; ++ struct hailo_vdma_enable_channels_params VdmaEnableChannels; ++ struct hailo_vdma_disable_channels_params VdmaDisableChannels; ++ struct hailo_vdma_interrupts_read_timestamp_params VdmaInterruptsReadTimestamps; ++ struct hailo_vdma_interrupts_wait_params VdmaInterruptsWait; ++ struct hailo_vdma_buffer_sync_params VdmaBufferSync; ++ struct hailo_fw_control FirmwareControl; ++ struct hailo_vdma_buffer_map_params VdmaBufferMap; ++ struct hailo_vdma_buffer_unmap_params VdmaBufferUnmap; ++ struct hailo_desc_list_create_params DescListCreate; ++ struct hailo_desc_list_release_params DescListReleaseParam; ++ struct hailo_desc_list_program_params DescListProgram; ++ struct hailo_d2h_notification D2HNotification; ++ struct hailo_device_properties DeviceProperties; ++ struct hailo_driver_info DriverInfo; ++ struct hailo_read_log_params ReadLog; ++ struct hailo_mark_as_in_use_params MarkAsInUse; ++ struct hailo_vdma_launch_transfer_params LaunchTransfer; ++ struct hailo_soc_connect_params ConnectParams; ++ struct hailo_soc_close_params SocCloseParams; ++ struct hailo_pci_ep_accept_params AcceptParams; ++ struct hailo_pci_ep_close_params PciEpCloseParams; ++ } Buffer; ++}; ++#endif // _MSC_VER ++ ++#pragma pack(pop) ++ ++enum hailo_general_ioctl_code { ++ HAILO_MEMORY_TRANSFER_CODE, ++ HAILO_QUERY_DEVICE_PROPERTIES_CODE, ++ HAILO_QUERY_DRIVER_INFO_CODE, ++ ++ // Must be last ++ HAILO_GENERAL_IOCTL_MAX_NR, ++}; ++ ++#define HAILO_MEMORY_TRANSFER _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_MEMORY_TRANSFER_CODE, struct hailo_memory_transfer_params) ++#define HAILO_QUERY_DEVICE_PROPERTIES _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DEVICE_PROPERTIES_CODE, struct hailo_device_properties) ++#define HAILO_QUERY_DRIVER_INFO _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DRIVER_INFO_CODE, struct hailo_driver_info) ++ ++enum hailo_vdma_ioctl_code { ++ HAILO_VDMA_ENABLE_CHANNELS_CODE, ++ HAILO_VDMA_DISABLE_CHANNELS_CODE, ++ HAILO_VDMA_INTERRUPTS_WAIT_CODE, ++ HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS_CODE, ++ HAILO_VDMA_BUFFER_MAP_CODE, ++ HAILO_VDMA_BUFFER_UNMAP_CODE, ++ HAILO_VDMA_BUFFER_SYNC_CODE, ++ HAILO_DESC_LIST_CREATE_CODE, ++ HAILO_DESC_LIST_RELEASE_CODE, ++ HAILO_DESC_LIST_PROGRAM_CODE, ++ HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, ++ HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE, ++ HAILO_MARK_AS_IN_USE_CODE, ++ HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE, ++ HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE, ++ HAILO_VDMA_LAUNCH_TRANSFER_CODE, ++ ++ // Must be last ++ HAILO_VDMA_IOCTL_MAX_NR, ++}; ++ ++#define HAILO_VDMA_ENABLE_CHANNELS _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_ENABLE_CHANNELS_CODE, struct hailo_vdma_enable_channels_params) ++#define HAILO_VDMA_DISABLE_CHANNELS _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_DISABLE_CHANNELS_CODE, struct hailo_vdma_disable_channels_params) ++#define HAILO_VDMA_INTERRUPTS_WAIT _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_WAIT_CODE, struct hailo_vdma_interrupts_wait_params) ++#define HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS_CODE, struct hailo_vdma_interrupts_read_timestamp_params) ++ ++#define HAILO_VDMA_BUFFER_MAP _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_MAP_CODE, struct hailo_vdma_buffer_map_params) ++#define HAILO_VDMA_BUFFER_UNMAP _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_UNMAP_CODE, struct hailo_vdma_buffer_unmap_params) ++#define HAILO_VDMA_BUFFER_SYNC _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_SYNC_CODE, struct hailo_vdma_buffer_sync_params) ++ ++#define HAILO_DESC_LIST_CREATE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_CREATE_CODE, struct hailo_desc_list_create_params) ++#define HAILO_DESC_LIST_RELEASE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_RELEASE_CODE, struct hailo_desc_list_release_params) ++#define HAILO_DESC_LIST_PROGRAM _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_PROGRAM_CODE, struct hailo_desc_list_program_params) ++ ++#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_low_memory_buffer_params) ++#define HAILO_VDMA_LOW_MEMORY_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE, struct hailo_free_low_memory_buffer_params) ++ ++#define HAILO_MARK_AS_IN_USE _IOW_(HAILO_VDMA_IOCTL_MAGIC, HAILO_MARK_AS_IN_USE_CODE, struct hailo_mark_as_in_use_params) ++ ++#define HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC_CODE, struct hailo_allocate_continuous_buffer_params) ++#define HAILO_VDMA_CONTINUOUS_BUFFER_FREE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CONTINUOUS_BUFFER_FREE_CODE, struct hailo_free_continuous_buffer_params) ++ ++#define HAILO_VDMA_LAUNCH_TRANSFER _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LAUNCH_TRANSFER_CODE, struct hailo_vdma_launch_transfer_params) ++ ++enum hailo_nnc_ioctl_code { ++ HAILO_FW_CONTROL_CODE, ++ HAILO_READ_NOTIFICATION_CODE, ++ HAILO_DISABLE_NOTIFICATION_CODE, ++ HAILO_READ_LOG_CODE, ++ HAILO_RESET_NN_CORE_CODE, ++ ++ // Must be last ++ HAILO_NNC_IOCTL_MAX_NR ++}; ++ ++#define HAILO_FW_CONTROL _IOWR_(HAILO_NNC_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control) ++#define HAILO_READ_NOTIFICATION _IOW_(HAILO_NNC_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification) ++#define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_NNC_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE) ++#define HAILO_READ_LOG _IOWR_(HAILO_NNC_IOCTL_MAGIC, HAILO_READ_LOG_CODE, struct hailo_read_log_params) ++#define HAILO_RESET_NN_CORE _IO_(HAILO_NNC_IOCTL_MAGIC, HAILO_RESET_NN_CORE_CODE) ++ ++enum hailo_soc_ioctl_code { ++ HAILO_SOC_IOCTL_CONNECT_CODE, ++ HAILO_SOC_IOCTL_CLOSE_CODE, ++ ++ // Must be last ++ HAILO_SOC_IOCTL_MAX_NR, ++}; ++ ++#define HAILO_SOC_CONNECT _IOWR_(HAILO_SOC_IOCTL_MAGIC, HAILO_SOC_IOCTL_CONNECT_CODE, struct hailo_soc_connect_params) ++#define HAILO_SOC_CLOSE _IOR_(HAILO_SOC_IOCTL_MAGIC, HAILO_SOC_IOCTL_CLOSE_CODE, struct hailo_soc_close_params) ++ ++ ++enum hailo_pci_ep_ioctl_code { ++ HAILO_PCI_EP_ACCEPT_CODE, ++ HAILO_PCI_EP_CLOSE_CODE, ++ ++ // Must be last ++ HAILO_PCI_EP_IOCTL_MAX_NR, ++}; ++ ++#define HAILO_PCI_EP_ACCEPT _IOWR_(HAILO_PCI_EP_IOCTL_MAGIC, HAILO_PCI_EP_ACCEPT_CODE, struct hailo_pci_ep_accept_params) ++#define HAILO_PCI_EP_CLOSE _IOR_(HAILO_PCI_EP_IOCTL_MAGIC, HAILO_PCI_EP_CLOSE_CODE, struct hailo_pci_ep_close_params) ++ ++#endif /* _HAILO_IOCTL_COMMON_H_ */ +diff --git a/drivers/media/pci/hailo/common/hailo_pcie_version.h b/drivers/media/pci/hailo/common/hailo_pcie_version.h +new file mode 100644 +index 000000000000..059e5d8a5c87 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/hailo_pcie_version.h +@@ -0,0 +1,13 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_COMMON_PCIE_VERSION_H_ ++#define _HAILO_COMMON_PCIE_VERSION_H_ ++ ++#define HAILO_DRV_VER_MAJOR 4 ++#define HAILO_DRV_VER_MINOR 17 ++#define HAILO_DRV_VER_REVISION 0 ++ ++#endif /* _HAILO_COMMON_PCIE_VERSION_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/hailo_resource.c b/drivers/media/pci/hailo/common/hailo_resource.c +new file mode 100644 +index 000000000000..05413e705d20 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/hailo_resource.c +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "hailo_resource.h" ++ ++#include ++#include ++#include ++#include ++ ++ ++u8 hailo_resource_read8(struct hailo_resource *resource, size_t offset) ++{ ++ return ioread8((u8*)resource->address + offset); ++} ++ ++u16 hailo_resource_read16(struct hailo_resource *resource, size_t offset) ++{ ++ return ioread16((u8*)resource->address + offset); ++} ++ ++u32 hailo_resource_read32(struct hailo_resource *resource, size_t offset) ++{ ++ return ioread32((u8*)resource->address + offset); ++} ++ ++void hailo_resource_write8(struct hailo_resource *resource, size_t offset, u8 value) ++{ ++ iowrite8(value, (u8*)resource->address + offset); ++} ++ ++void hailo_resource_write16(struct hailo_resource *resource, size_t offset, u16 value) ++{ ++ iowrite16(value, (u8*)resource->address + offset); ++} ++ ++void hailo_resource_write32(struct hailo_resource *resource, size_t offset, u32 value) ++{ ++ iowrite32(value, (u8*)resource->address + offset); ++} ++ ++void hailo_resource_read_buffer(struct hailo_resource *resource, size_t offset, size_t count, void *to) ++{ ++ // Copied and modified from linux aarch64 (using ioread32 instead of readq that does not work all the time) ++ uintptr_t to_ptr = (uintptr_t)to; ++ while ((count > 0) && (!IS_ALIGNED(to_ptr, 4) || !IS_ALIGNED((uintptr_t)resource->address + offset, 4))) { ++ *(u8*)to_ptr = hailo_resource_read8(resource, offset); ++ to_ptr++; ++ offset++; ++ count--; ++ } ++ ++ while (count >= 4) { ++ *(u32*)to_ptr = hailo_resource_read32(resource, offset); ++ to_ptr += 4; ++ offset += 4; ++ count -= 4; ++ } ++ ++ while (count > 0) { ++ *(u8*)to_ptr = hailo_resource_read8(resource, offset); ++ to_ptr++; ++ offset++; ++ count--; ++ } ++} ++ ++int hailo_resource_write_buffer(struct hailo_resource *resource, size_t offset, size_t count, const void *from) ++{ ++ // read the bytes after writing them for flushing the data. This function also checks if the pcie link ++ // is broken. ++ uintptr_t from_ptr = (uintptr_t)from; ++ while (count && (!IS_ALIGNED(resource->address + offset, 4) || !IS_ALIGNED(from_ptr, 4))) { ++ hailo_resource_write8(resource, offset, *(u8*)from_ptr); ++ if (hailo_resource_read8(resource, offset) != *(u8*)from_ptr) { ++ return -EIO; ++ } ++ from_ptr++; ++ offset++; ++ count--; ++ } ++ ++ while (count >= 4) { ++ hailo_resource_write32(resource, offset, *(u32*)from_ptr); ++ if (hailo_resource_read32(resource, offset) != *(u32*)from_ptr) { ++ return -EIO; ++ } ++ from_ptr += 4; ++ offset += 4; ++ count -= 4; ++ } ++ ++ while (count) { ++ hailo_resource_write8(resource, offset, *(u8*)from_ptr); ++ if (hailo_resource_read8(resource, offset) != *(u8*)from_ptr) { ++ return -EIO; ++ } ++ from_ptr++; ++ offset++; ++ count--; ++ } ++ ++ return 0; ++} ++ ++int hailo_resource_transfer(struct hailo_resource *resource, struct hailo_memory_transfer_params *transfer) ++{ ++ // Check for transfer size (address is in resources address-space) ++ if ((transfer->address + transfer->count) > (u64)resource->size) { ++ return -EINVAL; ++ } ++ ++ if (transfer->count > ARRAY_SIZE(transfer->buffer)) { ++ return -EINVAL; ++ } ++ ++ switch (transfer->transfer_direction) { ++ case TRANSFER_READ: ++ hailo_resource_read_buffer(resource, (u32)transfer->address, transfer->count, transfer->buffer); ++ return 0; ++ case TRANSFER_WRITE: ++ return hailo_resource_write_buffer(resource, (u32)transfer->address, transfer->count, transfer->buffer); ++ default: ++ return -EINVAL; ++ } ++} +diff --git a/drivers/media/pci/hailo/common/hailo_resource.h b/drivers/media/pci/hailo/common/hailo_resource.h +new file mode 100644 +index 000000000000..891a211fde33 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/hailo_resource.h +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_COMMON_HAILO_RESOURCE_H_ ++#define _HAILO_COMMON_HAILO_RESOURCE_H_ ++ ++#include "hailo_ioctl_common.h" ++#include ++ ++struct hailo_resource { ++ uintptr_t address; ++ size_t size; ++}; ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++// Implemented by the specific platform ++u32 hailo_resource_read32(struct hailo_resource *resource, size_t offset); ++u16 hailo_resource_read16(struct hailo_resource *resource, size_t offset); ++u8 hailo_resource_read8(struct hailo_resource *resource, size_t offset); ++void hailo_resource_write32(struct hailo_resource *resource, size_t offset, u32 value); ++void hailo_resource_write16(struct hailo_resource *resource, size_t offset, u16 value); ++void hailo_resource_write8(struct hailo_resource *resource, size_t offset, u8 value); ++ ++void hailo_resource_read_buffer(struct hailo_resource *resource, size_t offset, size_t count, void *to); ++int hailo_resource_write_buffer(struct hailo_resource *resource, size_t offset, size_t count, const void *from); ++ ++// Transfer (read/write) the given resource into/from transfer params. ++int hailo_resource_transfer(struct hailo_resource *resource, struct hailo_memory_transfer_params *transfer); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _HAILO_COMMON_HAILO_RESOURCE_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/pcie_common.c b/drivers/media/pci/hailo/common/pcie_common.c +new file mode 100644 +index 000000000000..a85787c03c9d +--- /dev/null ++++ b/drivers/media/pci/hailo/common/pcie_common.c +@@ -0,0 +1,872 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "pcie_common.h" ++#include "fw_operation.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define BSC_IMASK_HOST (0x0188) ++#define BCS_ISTATUS_HOST (0x018C) ++#define BCS_SOURCE_INTERRUPT_PER_CHANNEL (0x400) ++#define BCS_DESTINATION_INTERRUPT_PER_CHANNEL (0x500) ++ ++#define PO2_ROUND_UP(size, alignment) ((size + alignment-1) & ~(alignment-1)) ++ ++#define ATR_PARAM (0x17) ++#define ATR_SRC_ADDR (0x0) ++#define ATR_TRSL_PARAM (6) ++#define ATR_TABLE_SIZE (0x1000u) ++#define ATR_TABLE_SIZE_MASK (0x1000u - 1) ++ ++#define ATR0_PCIE_BRIDGE_OFFSET (0x700) ++ ++#define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000) ++#define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x20000) ++ ++#define FIRMWARE_LOAD_WAIT_MAX_RETRIES (100) ++#define FIRMWARE_LOAD_SLEEP_MS (50) ++ ++#define PCIE_APP_CPU_DEBUG_OFFSET (8*1024) ++#define PCIE_CORE_CPU_DEBUG_OFFSET (PCIE_APP_CPU_DEBUG_OFFSET + DEBUG_BUFFER_TOTAL_SIZE) ++ ++#define PCIE_D2H_NOTIFICATION_SRAM_OFFSET (0x640 + 0x640) ++#define PCIE_REQUEST_SIZE_OFFSET (0x640) ++ ++#define PCIE_CONFIG_VENDOR_OFFSET (0x0098) ++ ++#define HAILO_PCIE_HOST_DMA_DATA_ID (0) ++#define HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK (1 << 4) ++#define HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK (1 << 5) ++#define HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK (0x0000FFFF) ++ ++#define HAILO_PCIE_MAX_ATR_TABLE_INDEX (3) ++ ++#define MAX_FILES_PER_STAGE (4) ++ ++#define BOOT_STATUS_UNINITIALIZED (0x1) ++ ++struct hailo_fw_addresses { ++ u32 boot_fw_header; ++ u32 app_fw_code_ram_base; ++ u32 boot_key_cert; ++ u32 boot_cont_cert; ++ u32 boot_fw_trigger; ++ u32 core_code_ram_base; ++ u32 core_fw_header; ++ u32 atr0_trsl_addr1; ++ u32 raise_ready_offset; ++ u32 boot_status; ++}; ++ ++struct loading_stage { ++ const struct hailo_file_batch *batch; ++}; ++ ++struct hailo_board_compatibility { ++ struct hailo_fw_addresses fw_addresses; ++ const char *fw_filename; ++ const struct hailo_config_constants board_cfg; ++ const struct hailo_config_constants fw_cfg; ++ const struct loading_stage stages[MAX_LOADING_STAGES]; ++}; ++ ++static const struct hailo_file_batch hailo10h_files_stg1[] = { ++ { ++ .filename = "hailo/hailo10h/customer_certificate.bin", ++ .address = 0xA0000, ++ .max_size = 0x8004, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/u-boot.dtb.signed", ++ .address = 0xA8004, ++ .max_size = 0x20000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/scu_fw.bin", ++ .address = 0x20000, ++ .max_size = 0x40000, ++ .is_mandatory = true, ++ .has_header = true ++ }, ++ { ++ .filename = NULL, ++ .address = 0x00, ++ .max_size = 0x00, ++ .is_mandatory = false, ++ .has_header = false ++ } ++}; ++ ++static const struct hailo_file_batch hailo10h_files_stg2[] = { ++ { ++ .filename = "hailo/hailo10h/u-boot-spl.bin", ++ .address = 0x85000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/u-boot-tfa.itb", ++ .address = 0x86000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/fitImage", ++ .address = 0x87000000, ++ .max_size = 0x1000000, ++ .is_mandatory = true, ++ .has_header = false ++ }, ++ { ++ .filename = "hailo/hailo10h/core-image-minimal-hailo10-m2.ext4.gz", ++ .address = 0x88000000, ++ .max_size = 0x20000000, // Max size 512MB ++ .is_mandatory = true, ++ .has_header = false ++ }, ++}; ++ ++static const struct hailo_board_compatibility compat[HAILO_BOARD_TYPE_COUNT] = { ++ [HAILO_BOARD_TYPE_HAILO8] = { ++ .fw_addresses = { ++ .boot_fw_header = 0xE0030, ++ .boot_fw_trigger = 0xE0980, ++ .boot_key_cert = 0xE0048, ++ .boot_cont_cert = 0xE0390, ++ .app_fw_code_ram_base = 0x60000, ++ .core_code_ram_base = 0xC0000, ++ .core_fw_header = 0xA0000, ++ .atr0_trsl_addr1 = 0x60000000, ++ .raise_ready_offset = 0x1684, ++ .boot_status = 0xe0000, ++ }, ++ .fw_filename = "hailo/hailo8_fw.bin", ++ .board_cfg = { ++ .filename = "hailo/hailo8_board_cfg.bin", ++ .address = 0x60001000, ++ .max_size = PCIE_HAILO8_BOARD_CFG_MAX_SIZE, ++ }, ++ .fw_cfg = { ++ .filename = "hailo/hailo8_fw_cfg.bin", ++ .address = 0x60001500, ++ .max_size = PCIE_HAILO8_FW_CFG_MAX_SIZE, ++ }, ++ }, ++ [HAILO_BOARD_TYPE_HAILO10H_LEGACY] = { ++ .fw_addresses = { ++ .boot_fw_header = 0x88000, ++ .boot_fw_trigger = 0x88c98, ++ .boot_key_cert = 0x88018, ++ .boot_cont_cert = 0x886a8, ++ .app_fw_code_ram_base = 0x20000, ++ .core_code_ram_base = 0x60000, ++ .core_fw_header = 0xC0000, ++ .atr0_trsl_addr1 = 0x000BE000, ++ .raise_ready_offset = 0x1754, ++ .boot_status = 0x80000, ++ }, ++ .fw_filename = "hailo/hailo15_fw.bin", ++ .board_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .fw_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ }, ++ [HAILO_BOARD_TYPE_HAILO10H] = { ++ .fw_addresses = { ++ .boot_fw_header = 0x88000, ++ .boot_fw_trigger = 0x88c98, ++ .boot_key_cert = 0x88018, ++ .boot_cont_cert = 0x886a8, ++ .app_fw_code_ram_base = 0x20000, ++ .core_code_ram_base = 0, ++ .core_fw_header = 0, ++ .atr0_trsl_addr1 = 0x000BE000, ++ .raise_ready_offset = 0x1754, ++ .boot_status = 0x80000, ++ }, ++ .fw_filename = NULL, ++ .board_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .fw_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .stages = { ++ { ++ .batch = hailo10h_files_stg1, ++ }, ++ { ++ .batch = hailo10h_files_stg2, ++ }, ++ }, ++ }, ++ // HRT-11344 : none of these matter except raise_ready_offset seeing as we load fw seperately - not through driver ++ // After implementing bootloader put correct values here ++ [HAILO_BOARD_TYPE_PLUTO] = { ++ .fw_addresses = { ++ .boot_fw_header = 0x88000, ++ .boot_fw_trigger = 0x88c98, ++ .boot_key_cert = 0x88018, ++ .boot_cont_cert = 0x886a8, ++ .app_fw_code_ram_base = 0x20000, ++ .core_code_ram_base = 0x60000, ++ .core_fw_header = 0xC0000, ++ .atr0_trsl_addr1 = 0x000BE000, ++ // NOTE: After they update hw consts - check register fw_access_interrupt_w1s of pcie_config ++ .raise_ready_offset = 0x174c, ++ .boot_status = 0x80000, ++ }, ++ .fw_filename = "hailo/pluto_fw.bin", ++ .board_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ .fw_cfg = { ++ .filename = NULL, ++ .address = 0, ++ .max_size = 0, ++ }, ++ } ++}; ++ ++ ++bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source) ++{ ++ u32 channel_data_source = 0; ++ u32 channel_data_dest = 0; ++ memset(source, 0, sizeof(*source)); ++ ++ source->interrupt_bitmask = hailo_resource_read32(&resources->config, BCS_ISTATUS_HOST); ++ if (0 == source->interrupt_bitmask) { ++ return false; ++ } ++ ++ // clear signal ++ hailo_resource_write32(&resources->config, BCS_ISTATUS_HOST, source->interrupt_bitmask); ++ ++ if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK) { ++ channel_data_source = hailo_resource_read32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL); ++ hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, channel_data_source); ++ } ++ if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK) { ++ channel_data_dest = hailo_resource_read32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL); ++ hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, channel_data_dest); ++ } ++ source->vdma_channels_bitmap = channel_data_source | channel_data_dest; ++ ++ return true; ++} ++ ++int hailo_pcie_write_firmware_control(struct hailo_pcie_resources *resources, const struct hailo_fw_control *command) ++{ ++ int err = 0; ++ u32 request_size = 0; ++ u8 fw_access_value = FW_ACCESS_APP_CPU_CONTROL_MASK; ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ ++ if (!hailo_pcie_is_firmware_loaded(resources)) { ++ return -ENODEV; ++ } ++ ++ // Copy md5 + buffer_len + buffer ++ request_size = sizeof(command->expected_md5) + sizeof(command->buffer_len) + command->buffer_len; ++ err = hailo_resource_write_buffer(&resources->fw_access, 0, PO2_ROUND_UP(request_size, FW_CODE_SECTION_ALIGNMENT), ++ command); ++ if (err < 0) { ++ return err; ++ } ++ ++ // Raise the bit for the CPU that will handle the control ++ fw_access_value = (command->cpu_id == HAILO_CPU_ID_CPU1) ? FW_ACCESS_CORE_CPU_CONTROL_MASK : ++ FW_ACCESS_APP_CPU_CONTROL_MASK; ++ ++ // Raise ready flag to FW ++ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, (u32)fw_access_value); ++ return 0; ++} ++ ++int hailo_pcie_read_firmware_control(struct hailo_pcie_resources *resources, struct hailo_fw_control *command) ++{ ++ u32 response_header_size = 0; ++ ++ // Copy response md5 + buffer_len ++ response_header_size = sizeof(command->expected_md5) + sizeof(command->buffer_len); ++ ++ hailo_resource_read_buffer(&resources->fw_access, PCIE_REQUEST_SIZE_OFFSET, response_header_size, command); ++ ++ if (sizeof(command->buffer) < command->buffer_len) { ++ return -EINVAL; ++ } ++ ++ // Copy response buffer ++ hailo_resource_read_buffer(&resources->fw_access, PCIE_REQUEST_SIZE_OFFSET + (size_t)response_header_size, ++ command->buffer_len, &command->buffer); ++ ++ return 0; ++} ++ ++void hailo_pcie_write_firmware_driver_shutdown(struct hailo_pcie_resources *resources) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ const u32 fw_access_value = FW_ACCESS_DRIVER_SHUTDOWN_MASK; ++ ++ // Write shutdown flag to FW ++ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, fw_access_value); ++} ++ ++int hailo_pcie_read_firmware_notification(struct hailo_pcie_resources *resources, ++ struct hailo_d2h_notification *notification) ++{ ++ struct hailo_resource notification_resource; ++ ++ if (PCIE_D2H_NOTIFICATION_SRAM_OFFSET > resources->fw_access.size) { ++ return -EINVAL; ++ } ++ ++ notification_resource.address = resources->fw_access.address + PCIE_D2H_NOTIFICATION_SRAM_OFFSET, ++ notification_resource.size = sizeof(struct hailo_d2h_notification); ++ ++ return hailo_read_firmware_notification(¬ification_resource, notification); ++} ++ ++int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index) ++{ ++ size_t offset = 0; ++ struct hailo_atr_config atr = { ++ .atr_param = (ATR_PARAM | (atr_index << 12)), ++ .atr_src = ATR_SRC_ADDR, ++ .atr_trsl_addr_1 = (u32)(trsl_addr & 0xFFFFFFFF), ++ .atr_trsl_addr_2 = (u32)(trsl_addr >> 32), ++ .atr_trsl_param = ATR_TRSL_PARAM ++ }; ++ ++ BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); ++ offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ ++ return hailo_resource_write_buffer(bridge_config, offset, sizeof(atr), (void*)&atr); ++} ++ ++void hailo_pcie_read_atr_table(struct hailo_resource *bridge_config, struct hailo_atr_config *atr, u32 atr_index) ++{ ++ size_t offset = 0; ++ ++ BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); ++ offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ ++ hailo_resource_read_buffer(bridge_config, offset, sizeof(*atr), (void*)atr); ++} ++ ++static void write_memory_chunk(struct hailo_pcie_resources *resources, ++ hailo_ptr_t dest, u32 dest_offset, const void *src, u32 len) ++{ ++ u32 ATR_INDEX = 0; ++ BUG_ON(dest_offset + len > (u32)resources->fw_access.size); ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, (u64)dest, ATR_INDEX); ++ (void)hailo_resource_write_buffer(&resources->fw_access, dest_offset, len, src); ++} ++ ++static void read_memory_chunk( ++ struct hailo_pcie_resources *resources, hailo_ptr_t src, u32 src_offset, void *dest, u32 len) ++{ ++ u32 ATR_INDEX = 0; ++ BUG_ON(src_offset + len > (u32)resources->fw_access.size); ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, (u64)src, ATR_INDEX); ++ (void)hailo_resource_read_buffer(&resources->fw_access, src_offset, len, dest); ++} ++ ++// Note: this function modify the device ATR table (that is also used by the firmware for control and vdma). ++// Use with caution, and restore the original atr if needed. ++void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len) ++{ ++ struct hailo_atr_config previous_atr = {0}; ++ hailo_ptr_t base_address = (dest & ~ATR_TABLE_SIZE_MASK); ++ u32 chunk_len = 0; ++ u32 offset = 0; ++ u32 ATR_INDEX = 0; ++ ++ // Store previous ATR (Read/write modify the ATR). ++ hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX); ++ ++ if (base_address != dest) { ++ // Data is not aligned, write the first chunk ++ chunk_len = min(base_address + ATR_TABLE_SIZE - dest, len); ++ write_memory_chunk(resources, base_address, dest - base_address, src, chunk_len); ++ offset += chunk_len; ++ } ++ ++ while (offset < len) { ++ chunk_len = min(len - offset, ATR_TABLE_SIZE); ++ write_memory_chunk(resources, dest + offset, 0, (const u8*)src + offset, chunk_len); ++ offset += chunk_len; ++ } ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, ++ (((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX); ++} ++ ++// Note: this function modify the device ATR table (that is also used by the firmware for control and vdma). ++// Use with caution, and restore the original atr if needed. ++static void read_memory(struct hailo_pcie_resources *resources, hailo_ptr_t src, void *dest, u32 len) ++{ ++ struct hailo_atr_config previous_atr = {0}; ++ hailo_ptr_t base_address = (src & ~ATR_TABLE_SIZE_MASK); ++ u32 chunk_len = 0; ++ u32 offset = 0; ++ u32 ATR_INDEX = 0; ++ ++ // Store previous ATR (Read/write modify the ATR). ++ hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX); ++ ++ if (base_address != src) { ++ // Data is not aligned, write the first chunk ++ chunk_len = min(base_address + ATR_TABLE_SIZE - src, len); ++ read_memory_chunk(resources, base_address, src - base_address, dest, chunk_len); ++ offset += chunk_len; ++ } ++ ++ while (offset < len) { ++ chunk_len = min(len - offset, ATR_TABLE_SIZE); ++ read_memory_chunk(resources, src + offset, 0, (u8*)dest + offset, chunk_len); ++ offset += chunk_len; ++ } ++ ++ (void)hailo_pcie_configure_atr_table(&resources->config, ++ (((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX); ++} ++ ++static void hailo_write_app_firmware(struct hailo_pcie_resources *resources, firmware_header_t *fw_header, ++ secure_boot_certificate_t *fw_cert) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ void *fw_code = (void*)((u8*)fw_header + sizeof(firmware_header_t)); ++ void *key_data = &fw_cert->certificates_data[0]; ++ void *content_data = &fw_cert->certificates_data[fw_cert->key_size]; ++ ++ write_memory(resources, fw_addresses->boot_fw_header, fw_header, sizeof(firmware_header_t)); ++ ++ write_memory(resources, fw_addresses->app_fw_code_ram_base, fw_code, fw_header->code_size); ++ ++ write_memory(resources, fw_addresses->boot_key_cert, key_data, fw_cert->key_size); ++ write_memory(resources, fw_addresses->boot_cont_cert, content_data, fw_cert->content_size); ++} ++ ++static void hailo_write_core_firmware(struct hailo_pcie_resources *resources, firmware_header_t *fw_header) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ void *fw_code = (void*)((u8*)fw_header + sizeof(firmware_header_t)); ++ ++ write_memory(resources, fw_addresses->core_code_ram_base, fw_code, fw_header->code_size); ++ write_memory(resources, fw_addresses->core_fw_header, fw_header, sizeof(firmware_header_t)); ++} ++ ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ u32 pcie_finished = 1; ++ ++ write_memory(resources, fw_addresses->boot_fw_trigger, ++ (void*)&pcie_finished, sizeof(pcie_finished)); ++} ++ ++u32 hailo_get_boot_status(struct hailo_pcie_resources *resources) ++{ ++ u32 boot_status = 0; ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ ++ read_memory(resources, fw_addresses->boot_status, ++ &boot_status, sizeof(boot_status)); ++ ++ return boot_status; ++} ++ ++/** ++* Validates the FW headers. ++* @param[in] address Address of the firmware. ++* @param[in] firmware_size Size of the firmware. ++* @param[out] out_app_firmware_header (optional) App firmware header ++* @param[out] out_core_firmware_header (optional) Core firmware header ++* @param[out] out_firmware_cert (optional) Firmware certificate header ++*/ ++static int FW_VALIDATION__validate_fw_headers(uintptr_t firmware_base_address, size_t firmware_size, ++ firmware_header_t **out_app_firmware_header, firmware_header_t **out_core_firmware_header, ++ secure_boot_certificate_t **out_firmware_cert, enum hailo_board_type board_type) ++{ ++ firmware_header_t *app_firmware_header = NULL; ++ firmware_header_t *core_firmware_header = NULL; ++ secure_boot_certificate_t *firmware_cert = NULL; ++ int err = -EINVAL; ++ u32 consumed_firmware_offset = 0; ++ ++ err = FW_VALIDATION__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_APP_FIRMWARE_CODE_SIZE, ++ &consumed_firmware_offset, &app_firmware_header, board_type); ++ if (0 != err) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ err = FW_VALIDATION__validate_cert_header(firmware_base_address, firmware_size, ++ &consumed_firmware_offset, &firmware_cert); ++ if (0 != err) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ // Not validating with HAILO10H since core firmware doesn't loaded over pcie ++ if (HAILO_BOARD_TYPE_HAILO10H != board_type) { ++ err = FW_VALIDATION__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_CORE_FIRMWARE_CODE_SIZE, ++ &consumed_firmware_offset, &core_firmware_header, board_type); ++ if (0 != err) { ++ err = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (consumed_firmware_offset != firmware_size) { ++ /* it is an error if there is leftover data after the last firmware header */ ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* the out params are all optional */ ++ if (NULL != out_app_firmware_header) { ++ *out_app_firmware_header = app_firmware_header; ++ } ++ if (NULL != out_firmware_cert) { ++ *out_firmware_cert = firmware_cert; ++ } ++ if (NULL != out_core_firmware_header) { ++ *out_core_firmware_header = core_firmware_header; ++ } ++ err = 0; ++ ++exit: ++ return err; ++} ++ ++static int write_single_file(struct hailo_pcie_resources *resources, const struct hailo_file_batch *files_batch, struct device *dev) ++{ ++ const struct firmware *firmware = NULL; ++ firmware_header_t *app_firmware_header = NULL; ++ secure_boot_certificate_t *firmware_cert = NULL; ++ firmware_header_t *core_firmware_header = NULL; ++ int err = 0; ++ ++ err = request_firmware_direct(&firmware, files_batch->filename, dev); ++ if (err < 0) { ++ return err; ++ } ++ ++ if (firmware->size > files_batch->max_size) { ++ release_firmware(firmware); ++ return -EFBIG; ++ } ++ ++ if (files_batch->has_header) { ++ err = FW_VALIDATION__validate_fw_headers((uintptr_t)firmware->data, firmware->size, ++ &app_firmware_header, &core_firmware_header, &firmware_cert, resources->board_type); ++ if (err < 0) { ++ release_firmware(firmware); ++ return err; ++ } ++ ++ hailo_write_app_firmware(resources, app_firmware_header, firmware_cert); ++ } else { ++ write_memory(resources, files_batch->address, (void*)firmware->data, firmware->size); ++ } ++ ++ release_firmware(firmware); ++ ++ return 0; ++} ++ ++int hailo_pcie_write_firmware_batch(struct device *dev, struct hailo_pcie_resources *resources, u32 stage) ++{ ++ const struct hailo_file_batch *files_batch = compat[resources->board_type].stages[stage].batch; ++ int file_index = 0; ++ int err = 0; ++ ++ for (file_index = 0; file_index < MAX_FILES_PER_STAGE; file_index++) ++ { ++ if (NULL == files_batch[file_index].filename) { ++ break; ++ } ++ ++ dev_notice(dev, "Writing file %s\n", files_batch[file_index].filename); ++ ++ err = write_single_file(resources, &files_batch[file_index], dev); ++ if (err < 0) { ++ pr_warn("Failed to write file %s\n", files_batch[file_index].filename); ++ if (files_batch[file_index].is_mandatory) { ++ return err; ++ } ++ } ++ ++ dev_notice(dev, "File %s written successfully\n", files_batch[file_index].filename); ++ } ++ ++ return 0; ++} ++ ++int hailo_pcie_write_firmware(struct hailo_pcie_resources *resources, const void *fw_data, size_t fw_size) ++{ ++ firmware_header_t *app_firmware_header = NULL; ++ secure_boot_certificate_t *firmware_cert = NULL; ++ firmware_header_t *core_firmware_header = NULL; ++ ++ int err = FW_VALIDATION__validate_fw_headers((uintptr_t)fw_data, fw_size, ++ &app_firmware_header, &core_firmware_header, &firmware_cert, resources->board_type); ++ if (err < 0) { ++ return err; ++ } ++ ++ hailo_write_app_firmware(resources, app_firmware_header, firmware_cert); ++ hailo_write_core_firmware(resources, core_firmware_header); ++ ++ hailo_trigger_firmware_boot(resources); ++ ++ return 0; ++} ++ ++// TODO: HRT-14147 - remove this function ++bool hailo_pcie_is_device_ready_for_boot(struct hailo_pcie_resources *resources) ++{ ++ return hailo_get_boot_status(resources) == BOOT_STATUS_UNINITIALIZED; ++} ++ ++bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources) ++{ ++ u32 offset; ++ u32 atr_value; ++ ++ // TODO: HRT-14147 ++ if (HAILO_BOARD_TYPE_HAILO10H == resources->board_type) { ++ return !hailo_pcie_is_device_ready_for_boot(resources); ++ } ++ ++ offset = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1); ++ atr_value = hailo_resource_read32(&resources->config, offset); ++ ++ return atr_value == compat[resources->board_type].fw_addresses.atr0_trsl_addr1; ++} ++ ++bool hailo_pcie_wait_for_firmware(struct hailo_pcie_resources *resources) ++{ ++ size_t retries; ++ for (retries = 0; retries < FIRMWARE_LOAD_WAIT_MAX_RETRIES; retries++) { ++ if (hailo_pcie_is_firmware_loaded(resources)) { ++ return true; ++ } ++ ++ msleep(FIRMWARE_LOAD_SLEEP_MS); ++ } ++ ++ return false; ++} ++ ++int hailo_pcie_write_config_common(struct hailo_pcie_resources *resources, const void* config_data, ++ const size_t config_size, const struct hailo_config_constants *config_consts) ++{ ++ if (config_size > config_consts->max_size) { ++ return -EINVAL; ++ } ++ ++ write_memory(resources, config_consts->address, config_data, (u32)config_size); ++ return 0; ++} ++ ++const struct hailo_config_constants* hailo_pcie_get_board_config_constants(const enum hailo_board_type board_type) { ++ BUG_ON(board_type >= HAILO_BOARD_TYPE_COUNT || board_type < 0); ++ return &compat[board_type].board_cfg; ++} ++ ++const struct hailo_config_constants* hailo_pcie_get_user_config_constants(const enum hailo_board_type board_type) { ++ BUG_ON(board_type >= HAILO_BOARD_TYPE_COUNT || board_type < 0); ++ return &compat[board_type].fw_cfg; ++} ++ ++const char* hailo_pcie_get_fw_filename(const enum hailo_board_type board_type) { ++ BUG_ON(board_type >= HAILO_BOARD_TYPE_COUNT || board_type < 0); ++ return compat[board_type].fw_filename; ++} ++ ++void hailo_pcie_update_channel_interrupts_mask(struct hailo_pcie_resources* resources, u32 channels_bitmap) ++{ ++ size_t i = 0; ++ u32 mask = hailo_resource_read32(&resources->config, BSC_IMASK_HOST); ++ ++ // Clear old channel interrupts ++ mask &= ~BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK; ++ mask &= ~BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK; ++ // Set interrupt by the bitmap ++ for (i = 0; i < MAX_VDMA_CHANNELS_PER_ENGINE; ++i) { ++ if (hailo_test_bit(i, &channels_bitmap)) { ++ // based on 18.5.2 "vDMA Interrupt Registers" in PLDA documentation ++ u32 offset = (i & 16) ? 8 : 0; ++ hailo_set_bit((((int)i*8) / MAX_VDMA_CHANNELS_PER_ENGINE) + offset, &mask); ++ } ++ } ++ hailo_resource_write32(&resources->config, BSC_IMASK_HOST, mask); ++} ++ ++void hailo_pcie_enable_interrupts(struct hailo_pcie_resources *resources) ++{ ++ u32 mask = hailo_resource_read32(&resources->config, BSC_IMASK_HOST); ++ ++ hailo_resource_write32(&resources->config, BCS_ISTATUS_HOST, 0xFFFFFFFF); ++ hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF); ++ hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF); ++ ++ mask |= (BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK | BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION | ++ BCS_ISTATUS_HOST_DRIVER_DOWN | BCS_ISTATUS_SOC_CONNECT_ACCEPTED); ++ hailo_resource_write32(&resources->config, BSC_IMASK_HOST, mask); ++} ++ ++void hailo_pcie_disable_interrupts(struct hailo_pcie_resources* resources) ++{ ++ hailo_resource_write32(&resources->config, BSC_IMASK_HOST, 0); ++} ++ ++long hailo_pcie_read_firmware_log(struct hailo_pcie_resources *resources, struct hailo_read_log_params *params) ++{ ++ long err = 0; ++ struct hailo_resource log_resource = {resources->fw_access.address, DEBUG_BUFFER_TOTAL_SIZE}; ++ ++ if (HAILO_CPU_ID_CPU0 == params->cpu_id) { ++ log_resource.address += PCIE_APP_CPU_DEBUG_OFFSET; ++ } else if (HAILO_CPU_ID_CPU1 == params->cpu_id) { ++ log_resource.address += PCIE_CORE_CPU_DEBUG_OFFSET; ++ } else { ++ return -EINVAL; ++ } ++ ++ if (0 == params->buffer_size) { ++ params->read_bytes = 0; ++ return 0; ++ } ++ ++ err = hailo_read_firmware_log(&log_resource, params); ++ if (0 != err) { ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int direct_memory_transfer(struct hailo_pcie_resources *resources, ++ struct hailo_memory_transfer_params *params) ++{ ++ if (params->address > U32_MAX) { ++ return -EFAULT; ++ } ++ ++ switch (params->transfer_direction) { ++ case TRANSFER_READ: ++ read_memory(resources, (u32)params->address, params->buffer, (u32)params->count); ++ break; ++ case TRANSFER_WRITE: ++ write_memory(resources, (u32)params->address, params->buffer, (u32)params->count); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int hailo_pcie_memory_transfer(struct hailo_pcie_resources *resources, struct hailo_memory_transfer_params *params) ++{ ++ if (params->count > ARRAY_SIZE(params->buffer)) { ++ return -EINVAL; ++ } ++ ++ switch (params->memory_type) { ++ case HAILO_TRANSFER_DEVICE_DIRECT_MEMORY: ++ return direct_memory_transfer(resources, params); ++ case HAILO_TRANSFER_MEMORY_PCIE_BAR0: ++ return hailo_resource_transfer(&resources->config, params); ++ case HAILO_TRANSFER_MEMORY_PCIE_BAR2: ++ case HAILO_TRANSFER_MEMORY_VDMA0: ++ return hailo_resource_transfer(&resources->vdma_registers, params); ++ case HAILO_TRANSFER_MEMORY_PCIE_BAR4: ++ return hailo_resource_transfer(&resources->fw_access, params); ++ default: ++ return -EINVAL; ++ } ++} ++ ++bool hailo_pcie_is_device_connected(struct hailo_pcie_resources *resources) ++{ ++ return PCI_VENDOR_ID_HAILO == hailo_resource_read16(&resources->config, PCIE_CONFIG_VENDOR_OFFSET); ++} ++ ++int hailo_set_device_type(struct hailo_pcie_resources *resources) ++{ ++ switch(resources->board_type) { ++ case HAILO_BOARD_TYPE_HAILO8: ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: ++ case HAILO_BOARD_TYPE_PLUTO: ++ resources->accelerator_type = HAILO_ACCELERATOR_TYPE_NNC; ++ break; ++ case HAILO_BOARD_TYPE_HAILO10H: ++ resources->accelerator_type = HAILO_ACCELERATOR_TYPE_SOC; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++// On PCIe, just return the address ++static u64 encode_dma_address(dma_addr_t dma_address, u8 channel_id) ++{ ++ (void)channel_id; ++ return (u64)dma_address; ++} ++ ++struct hailo_vdma_hw hailo_pcie_vdma_hw = { ++ .hw_ops = { ++ .encode_desc_dma_address = encode_dma_address ++ }, ++ .ddr_data_id = HAILO_PCIE_HOST_DMA_DATA_ID, ++ .device_interrupts_bitmask = HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK, ++ .host_interrupts_bitmask = HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK, ++ .src_channels_bitmask = HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK, ++}; ++ ++void hailo_soc_write_soc_connect(struct hailo_pcie_resources *resources) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ const u32 soc_connect_value = FW_ACCESS_SOC_CONNECT_MASK; ++ ++ // Write shutdown flag to FW ++ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, soc_connect_value); ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/pcie_common.h b/drivers/media/pci/hailo/common/pcie_common.h +new file mode 100644 +index 000000000000..642391c58999 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/pcie_common.h +@@ -0,0 +1,168 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_COMMON_PCIE_COMMON_H_ ++#define _HAILO_COMMON_PCIE_COMMON_H_ ++ ++#include "hailo_resource.h" ++#include "hailo_ioctl_common.h" ++#include "fw_validation.h" ++#include "fw_operation.h" ++#include "utils.h" ++#include "vdma_common.h" ++ ++#include ++#include ++ ++ ++#define BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK (0x04000000) ++#define BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION (0x02000000) ++#define BCS_ISTATUS_HOST_DRIVER_DOWN (0x08000000) ++#define BCS_ISTATUS_SOC_CONNECT_ACCEPTED (0x10000000) ++#define BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK (0x000000FF) ++#define BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK (0x0000FF00) ++ ++#define PCIE_HAILO8_BOARD_CFG_MAX_SIZE (0x500) ++#define PCIE_HAILO8_FW_CFG_MAX_SIZE (0x500) ++ ++#define FW_CODE_SECTION_ALIGNMENT (4) ++ ++#define HAILO_PCIE_CONFIG_BAR (0) ++#define HAILO_PCIE_VDMA_REGS_BAR (2) ++#define HAILO_PCIE_FW_ACCESS_BAR (4) ++ ++#define HAILO_PCIE_DMA_ENGINES_COUNT (1) ++ ++#define DRIVER_NAME "hailo" ++ ++#define PCI_VENDOR_ID_HAILO 0x1e60 ++#define PCI_DEVICE_ID_HAILO_HAILO8 0x2864 ++#define PCI_DEVICE_ID_HAILO_HAILO15 0x45C4 ++#define PCI_DEVICE_ID_HAILO_PLUTO 0x43a2 ++ ++typedef u32 hailo_ptr_t; ++ ++struct hailo_pcie_resources { ++ struct hailo_resource config; // BAR0 ++ struct hailo_resource vdma_registers; // BAR2 ++ struct hailo_resource fw_access; // BAR4 ++ enum hailo_board_type board_type; ++ enum hailo_accelerator_type accelerator_type; ++}; ++ ++struct hailo_atr_config { ++ u32 atr_param; ++ u32 atr_src; ++ u32 atr_trsl_addr_1; ++ u32 atr_trsl_addr_2; ++ u32 atr_trsl_param; ++}; ++ ++enum loading_stages { ++ FIRST_STAGE = 0, ++ SECOND_STAGE = 1, ++ MAX_LOADING_STAGES = 2 ++}; ++ ++enum hailo_pcie_interrupt_masks { ++ FW_CONTROL = BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK, ++ FW_NOTIFICATION = BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION, ++ DRIVER_DOWN = BCS_ISTATUS_HOST_DRIVER_DOWN, ++ SOC_CONNECT_ACCEPTED = BCS_ISTATUS_SOC_CONNECT_ACCEPTED, ++ VDMA_SRC_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK, ++ VDMA_DEST_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK ++}; ++ ++struct hailo_pcie_interrupt_source { ++ u32 interrupt_bitmask; ++ u32 vdma_channels_bitmap; ++}; ++ ++struct hailo_config_constants { ++ const char *filename; ++ u32 address; ++ size_t max_size; ++}; ++ ++struct hailo_file_batch { ++ const char *filename; ++ u32 address; ++ size_t max_size; ++ bool is_mandatory; ++ bool has_header; ++}; ++ ++// TODO: HRT-6144 - Align Windows/Linux to QNX ++#ifdef __QNX__ ++enum hailo_bar_index { ++ BAR0 = 0, ++ BAR2, ++ BAR4, ++ MAX_BAR ++}; ++#else ++enum hailo_bar_index { ++ BAR0 = 0, ++ BAR1, ++ BAR2, ++ BAR3, ++ BAR4, ++ BAR5, ++ MAX_BAR ++}; ++#endif // ifdef (__QNX__) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern struct hailo_vdma_hw hailo_pcie_vdma_hw; ++ ++// Reads the interrupt source from BARs, return false if there is no interrupt. ++// note - this function clears the interrupt signals. ++bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source); ++void hailo_pcie_update_channel_interrupts_mask(struct hailo_pcie_resources *resources, u32 channels_bitmap); ++void hailo_pcie_enable_interrupts(struct hailo_pcie_resources *resources); ++void hailo_pcie_disable_interrupts(struct hailo_pcie_resources *resources); ++ ++int hailo_pcie_write_firmware_control(struct hailo_pcie_resources *resources, const struct hailo_fw_control *command); ++int hailo_pcie_read_firmware_control(struct hailo_pcie_resources *resources, struct hailo_fw_control *command); ++ ++int hailo_pcie_write_firmware(struct hailo_pcie_resources *resources, const void *fw_data, size_t fw_size); ++int hailo_pcie_write_firmware_batch(struct device *dev, struct hailo_pcie_resources *resources, u32 stage); ++bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources); ++bool hailo_pcie_wait_for_firmware(struct hailo_pcie_resources *resources); ++ ++int hailo_pcie_read_firmware_notification(struct hailo_pcie_resources *resources, ++ struct hailo_d2h_notification *notification); ++ ++int hailo_pcie_write_config_common(struct hailo_pcie_resources *resources, const void* config_data, ++ const size_t config_size, const struct hailo_config_constants *config_consts); ++const struct hailo_config_constants* hailo_pcie_get_board_config_constants(const enum hailo_board_type board_type); ++const struct hailo_config_constants* hailo_pcie_get_user_config_constants(const enum hailo_board_type board_type); ++const char* hailo_pcie_get_fw_filename(const enum hailo_board_type board_type); ++ ++long hailo_pcie_read_firmware_log(struct hailo_pcie_resources *resources, struct hailo_read_log_params *params); ++int hailo_pcie_memory_transfer(struct hailo_pcie_resources *resources, struct hailo_memory_transfer_params *params); ++ ++bool hailo_pcie_is_device_connected(struct hailo_pcie_resources *resources); ++void hailo_pcie_write_firmware_driver_shutdown(struct hailo_pcie_resources *resources); ++void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len); ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources); ++ ++int hailo_set_device_type(struct hailo_pcie_resources *resources); ++ ++u32 hailo_get_boot_status(struct hailo_pcie_resources *resources); ++ ++int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index); ++void hailo_pcie_read_atr_table(struct hailo_resource *bridge_config, struct hailo_atr_config *atr, u32 atr_index); ++ ++void hailo_soc_write_soc_connect(struct hailo_pcie_resources *resources); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _HAILO_COMMON_PCIE_COMMON_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/utils.h b/drivers/media/pci/hailo/common/utils.h +new file mode 100644 +index 000000000000..fcf34978c807 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/utils.h +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_DRIVER_UTILS_H_ ++#define _HAILO_DRIVER_UTILS_H_ ++ ++#include ++ ++#define hailo_clear_bit(bit, pval) { *(pval) &= ~(1 << bit); } ++#define hailo_test_bit(pos,var_addr) ((*var_addr) & (1<<(pos))) ++ ++#define READ_BITS_AT_OFFSET(amount_bits, offset, initial_value) \ ++ (((initial_value) >> (offset)) & ((1 << (amount_bits)) - 1)) ++#define WRITE_BITS_AT_OFFSET(amount_bits, offset, initial_value, value) \ ++ (((initial_value) & ~(((1 << (amount_bits)) - 1) << (offset))) | \ ++ (((value) & ((1 << (amount_bits)) - 1)) << (offset))) ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++static inline bool is_powerof2(size_t v) { ++ // bit trick ++ return (v & (v - 1)) == 0; ++} ++ ++static inline void hailo_set_bit(int nr, u32* addr) { ++ u32 mask = BIT_MASK(nr); ++ u32 *p = addr + BIT_WORD(nr); ++ ++ *p |= mask; ++} ++ ++static inline uint8_t ceil_log2(uint32_t n) ++{ ++ uint8_t result = 0; ++ ++ if (n <= 1) { ++ return 0; ++ } ++ ++ while (n > 1) { ++ result++; ++ n = (n + 1) >> 1; ++ } ++ ++ return result; ++} ++ ++#ifndef DIV_ROUND_UP ++#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // _HAILO_DRIVER_UTILS_H_ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/vdma_common.c b/drivers/media/pci/hailo/common/vdma_common.c +new file mode 100644 +index 000000000000..c8b60c848416 +--- /dev/null ++++ b/drivers/media/pci/hailo/common/vdma_common.c +@@ -0,0 +1,877 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "vdma_common.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5) ++ ++#define CHANNEL_CONTROL_OFFSET (0x0) ++#define CHANNEL_DEPTH_ID_OFFSET (0x1) ++#define CHANNEL_NUM_AVAIL_OFFSET (0x2) ++#define CHANNEL_NUM_PROC_OFFSET (0x4) ++#define CHANNEL_ERROR_OFFSET (0x8) ++#define CHANNEL_DEST_REGS_OFFSET (0x10) ++ ++#define VDMA_CHANNEL_CONTROL_START (0x1) ++#define VDMA_CHANNEL_CONTROL_ABORT (0b00) ++#define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10) ++#define VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK (0x3) ++#define VDMA_CHANNEL_CONTROL_START_ABORT_BITMASK (0x1) ++#define VDMA_CHANNEL_CONTROL_MASK (0xFC) ++#define VDMA_CHANNEL_CONTROL_START_RESUME (0b01) ++#define VDMA_CHANNEL_CONTROL_START_PAUSE (0b11) ++#define VDMA_CHANNEL_CONTROL_ABORT (0b00) ++#define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10) ++#define VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK (0x3) ++#define VDMA_CHANNEL_DESC_DEPTH_WIDTH (4) ++#define VDMA_CHANNEL_DESC_DEPTH_SHIFT (11) ++#define VDMA_CHANNEL_DATA_ID_SHIFT (8) ++#define VDMA_CHANNEL__MAX_CHECKS_CHANNEL_IS_IDLE (10000) ++#define VDMA_CHANNEL__ADDRESS_L_OFFSET (0x0A) ++#define VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET (0x8) ++#define VDMA_CHANNEL__ADDRESS_H_OFFSET (0x0C) ++ ++#define DESCRIPTOR_PAGE_SIZE_SHIFT (8) ++#define DESCRIPTOR_DESC_CONTROL (0x2) ++#define DESCRIPTOR_ADDR_L_MASK (0xFFFFFFC0) ++#define DESCRIPTOR_LIST_MAX_DEPTH (16) ++ ++#define DESCRIPTOR_DESC_STATUS_DONE_BIT (0x0) ++#define DESCRIPTOR_DESC_STATUS_ERROR_BIT (0x1) ++#define DESCRIPTOR_DESC_STATUS_MASK (0xFF) ++ ++#define DESC_STATUS_REQ (1 << 0) ++#define DESC_STATUS_REQ_ERR (1 << 1) ++#define DESC_REQUEST_IRQ_PROCESSED (1 << 2) ++#define DESC_REQUEST_IRQ_ERR (1 << 3) ++ ++#define VDMA_CHANNEL_NUM_PROCESSED_WIDTH (16) ++#define VDMA_CHANNEL_NUM_PROCESSED_MASK ((1 << VDMA_CHANNEL_NUM_PROCESSED_WIDTH) - 1) ++#define VDMA_CHANNEL_NUM_ONGOING_MASK VDMA_CHANNEL_NUM_PROCESSED_MASK ++ ++#define DWORD_SIZE (4) ++#define WORD_SIZE (2) ++#define BYTE_SIZE (1) ++#define BITS_IN_BYTE (8) ++ ++#define TIMESTAMPS_CIRC_SPACE(timestamp_list) \ ++ CIRC_SPACE((timestamp_list).head, (timestamp_list).tail, CHANNEL_IRQ_TIMESTAMPS_SIZE) ++#define TIMESTAMPS_CIRC_CNT(timestamp_list) \ ++ CIRC_CNT((timestamp_list).head, (timestamp_list).tail, CHANNEL_IRQ_TIMESTAMPS_SIZE) ++ ++#define ONGOING_TRANSFERS_CIRC_SPACE(transfers_list) \ ++ CIRC_SPACE((transfers_list).head, (transfers_list).tail, HAILO_VDMA_MAX_ONGOING_TRANSFERS) ++#define ONGOING_TRANSFERS_CIRC_CNT(transfers_list) \ ++ CIRC_CNT((transfers_list).head, (transfers_list).tail, HAILO_VDMA_MAX_ONGOING_TRANSFERS) ++ ++#ifndef for_each_sgtable_dma_sg ++#define for_each_sgtable_dma_sg(sgt, sg, i) \ ++ for_each_sg((sgt)->sgl, sg, (sgt)->nents, i) ++#endif /* for_each_sgtable_dma_sg */ ++ ++ ++static int ongoing_transfer_push(struct hailo_vdma_channel *channel, ++ struct hailo_ongoing_transfer *ongoing_transfer) ++{ ++ struct hailo_ongoing_transfers_list *transfers = &channel->ongoing_transfers; ++ if (!ONGOING_TRANSFERS_CIRC_SPACE(*transfers)) { ++ return -EFAULT; ++ } ++ ++ if (ongoing_transfer->dirty_descs_count > ARRAY_SIZE(ongoing_transfer->dirty_descs)) { ++ return -EFAULT; ++ } ++ ++ transfers->transfers[transfers->head] = *ongoing_transfer; ++ transfers->head = (transfers->head + 1) & HAILO_VDMA_MAX_ONGOING_TRANSFERS_MASK; ++ return 0; ++} ++ ++static int ongoing_transfer_pop(struct hailo_vdma_channel *channel, ++ struct hailo_ongoing_transfer *ongoing_transfer) ++{ ++ struct hailo_ongoing_transfers_list *transfers = &channel->ongoing_transfers; ++ if (!ONGOING_TRANSFERS_CIRC_CNT(*transfers)) { ++ return -EFAULT; ++ } ++ ++ if (ongoing_transfer) { ++ *ongoing_transfer = transfers->transfers[transfers->tail]; ++ } ++ transfers->tail = (transfers->tail + 1) & HAILO_VDMA_MAX_ONGOING_TRANSFERS_MASK; ++ return 0; ++} ++ ++static void clear_dirty_desc(struct hailo_vdma_descriptors_list *desc_list, u16 desc) ++{ ++ desc_list->desc_list[desc].PageSize_DescControl = ++ (u32)((desc_list->desc_page_size << DESCRIPTOR_PAGE_SIZE_SHIFT) + DESCRIPTOR_DESC_CONTROL); ++} ++ ++static void clear_dirty_descs(struct hailo_vdma_channel *channel, ++ struct hailo_ongoing_transfer *ongoing_transfer) ++{ ++ u8 i = 0; ++ struct hailo_vdma_descriptors_list *desc_list = channel->last_desc_list; ++ BUG_ON(ongoing_transfer->dirty_descs_count > ARRAY_SIZE(ongoing_transfer->dirty_descs)); ++ for (i = 0; i < ongoing_transfer->dirty_descs_count; i++) { ++ clear_dirty_desc(desc_list, ongoing_transfer->dirty_descs[i]); ++ } ++} ++ ++static bool validate_last_desc_status(struct hailo_vdma_channel *channel, ++ struct hailo_ongoing_transfer *ongoing_transfer) ++{ ++ u16 last_desc = ongoing_transfer->last_desc; ++ u32 last_desc_control = channel->last_desc_list->desc_list[last_desc].RemainingPageSize_Status & ++ DESCRIPTOR_DESC_STATUS_MASK; ++ if (!hailo_test_bit(DESCRIPTOR_DESC_STATUS_DONE_BIT, &last_desc_control)) { ++ pr_err("Expecting desc %d to be done\n", last_desc); ++ return false; ++ } ++ if (hailo_test_bit(DESCRIPTOR_DESC_STATUS_ERROR_BIT, &last_desc_control)) { ++ pr_err("Got unexpected error on desc %d\n", last_desc); ++ return false; ++ } ++ ++ return true; ++} ++ ++void hailo_vdma_program_descriptor(struct hailo_vdma_descriptor *descriptor, u64 dma_address, size_t page_size, ++ u8 data_id) ++{ ++ descriptor->PageSize_DescControl = (u32)((page_size << DESCRIPTOR_PAGE_SIZE_SHIFT) + ++ DESCRIPTOR_DESC_CONTROL); ++ descriptor->AddrL_rsvd_DataID = (u32)(((dma_address & DESCRIPTOR_ADDR_L_MASK)) | data_id); ++ descriptor->AddrH = (u32)(dma_address >> 32); ++ descriptor->RemainingPageSize_Status = 0 ; ++} ++ ++static u8 get_channel_id(u8 channel_index) ++{ ++ return (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE) ? (channel_index & 0xF) : INVALID_VDMA_CHANNEL; ++} ++ ++static int program_descriptors_in_chunk( ++ struct hailo_vdma_hw *vdma_hw, ++ dma_addr_t chunk_addr, ++ unsigned int chunk_size, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 desc_index, ++ u32 max_desc_index, ++ u8 channel_id) ++{ ++ const u32 desc_per_chunk = DIV_ROUND_UP(chunk_size, desc_list->desc_page_size); ++ struct hailo_vdma_descriptor *dma_desc = NULL; ++ u16 size_to_program = 0; ++ u32 index = 0; ++ u64 encoded_addr = 0; ++ ++ for (index = 0; index < desc_per_chunk; index++) { ++ if (desc_index > max_desc_index) { ++ return -ERANGE; ++ } ++ ++ encoded_addr = vdma_hw->hw_ops.encode_desc_dma_address(chunk_addr, channel_id); ++ if (INVALID_VDMA_ADDRESS == encoded_addr) { ++ return -EFAULT; ++ } ++ ++ dma_desc = &desc_list->desc_list[desc_index % desc_list->desc_count]; ++ size_to_program = chunk_size > desc_list->desc_page_size ? ++ desc_list->desc_page_size : (u16)chunk_size; ++ hailo_vdma_program_descriptor(dma_desc, encoded_addr, size_to_program, vdma_hw->ddr_data_id); ++ ++ chunk_addr += size_to_program; ++ chunk_size -= size_to_program; ++ desc_index++; ++ } ++ ++ return (int)desc_per_chunk; ++} ++ ++static unsigned long get_interrupts_bitmask(struct hailo_vdma_hw *vdma_hw, ++ enum hailo_vdma_interrupts_domain interrupts_domain, bool is_debug) ++{ ++ unsigned long bitmask = 0; ++ ++ if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_DEVICE & interrupts_domain)) { ++ bitmask |= vdma_hw->device_interrupts_bitmask; ++ } ++ if (0 != (HAILO_VDMA_INTERRUPTS_DOMAIN_HOST & interrupts_domain)) { ++ bitmask |= vdma_hw->host_interrupts_bitmask; ++ } ++ ++ if (bitmask != 0) { ++ bitmask |= DESC_REQUEST_IRQ_PROCESSED | DESC_REQUEST_IRQ_ERR; ++ if (is_debug) { ++ bitmask |= DESC_STATUS_REQ | DESC_STATUS_REQ_ERR; ++ } ++ } ++ ++ return bitmask; ++} ++ ++static int bind_and_program_descriptors_list( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *buffer, ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ const u8 channel_id = get_channel_id(channel_index); ++ int desc_programmed = 0; ++ u32 max_desc_index = 0; ++ u32 chunk_size = 0; ++ struct scatterlist *sg_entry = NULL; ++ unsigned int i = 0; ++ int ret = 0; ++ size_t buffer_current_offset = 0; ++ dma_addr_t chunk_start_addr = 0; ++ u32 program_size = buffer->size; ++ ++ if (starting_desc >= desc_list->desc_count) { ++ return -EFAULT; ++ } ++ ++ if (buffer->offset % desc_list->desc_page_size != 0) { ++ return -EFAULT; ++ } ++ ++ // On circular buffer, allow programming desc_count descriptors (starting ++ // from starting_desc). On non circular, don't allow is to pass desc_count ++ max_desc_index = desc_list->is_circular ? ++ starting_desc + desc_list->desc_count - 1 : ++ desc_list->desc_count - 1; ++ for_each_sgtable_dma_sg(buffer->sg_table, sg_entry, i) { ++ // Skip sg entries until we reach the right buffer offset. offset can be in the middle of an sg entry. ++ if (buffer_current_offset + sg_dma_len(sg_entry) < buffer->offset) { ++ buffer_current_offset += sg_dma_len(sg_entry); ++ continue; ++ } ++ chunk_start_addr = (buffer_current_offset < buffer->offset) ? ++ sg_dma_address(sg_entry) + (buffer->offset - buffer_current_offset) : ++ sg_dma_address(sg_entry); ++ chunk_size = (buffer_current_offset < buffer->offset) ? ++ (u32)(sg_dma_len(sg_entry) - (buffer->offset - buffer_current_offset)) : ++ (u32)(sg_dma_len(sg_entry)); ++ chunk_size = min((u32)program_size, chunk_size); ++ ++ ret = program_descriptors_in_chunk(vdma_hw, chunk_start_addr, chunk_size, desc_list, ++ starting_desc, max_desc_index, channel_id); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ desc_programmed += ret; ++ starting_desc = starting_desc + ret; ++ program_size -= chunk_size; ++ buffer_current_offset += sg_dma_len(sg_entry); ++ } ++ ++ if (program_size != 0) { ++ // We didn't program all the buffer. ++ return -EFAULT; ++ } ++ ++ desc_list->desc_list[(starting_desc - 1) % desc_list->desc_count].PageSize_DescControl |= ++ get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug); ++ ++ return desc_programmed; ++} ++ ++static int program_last_desc( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *transfer_buffer, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ u8 control = (u8)(DESCRIPTOR_DESC_CONTROL | get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug)); ++ u32 total_descs = DIV_ROUND_UP(transfer_buffer->size, desc_list->desc_page_size); ++ u32 last_desc = (starting_desc + total_descs - 1) % desc_list->desc_count; ++ u32 last_desc_size = transfer_buffer->size - (total_descs - 1) * desc_list->desc_page_size; ++ ++ // Configure only last descriptor with residue size ++ desc_list->desc_list[last_desc].PageSize_DescControl = (u32) ++ ((last_desc_size << DESCRIPTOR_PAGE_SIZE_SHIFT) + control); ++ return (int)total_descs; ++} ++ ++int hailo_vdma_program_descriptors_list( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *buffer, ++ bool should_bind, ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ return should_bind ? ++ bind_and_program_descriptors_list(vdma_hw, desc_list, starting_desc, ++ buffer, channel_index, last_desc_interrupts, is_debug) : ++ program_last_desc(vdma_hw, desc_list, starting_desc, buffer, ++ last_desc_interrupts, is_debug); ++} ++ ++ ++static bool channel_control_reg_is_active(u8 control) ++{ ++ return (control & VDMA_CHANNEL_CONTROL_START_ABORT_BITMASK) == VDMA_CHANNEL_CONTROL_START; ++} ++ ++static int validate_channel_state(struct hailo_vdma_channel *channel) ++{ ++ u32 host_regs_value = ioread32(channel->host_regs); ++ const u8 control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value); ++ const u16 hw_num_avail = READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_value); ++ ++ if (!channel_control_reg_is_active(control)) { ++ return -ECONNRESET; ++ } ++ ++ if (hw_num_avail != channel->state.num_avail) { ++ pr_err("Channel %d hw state out of sync. num available is %d, expected %d\n", ++ channel->index, hw_num_avail, channel->state.num_avail); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static void set_num_avail(u8 __iomem *host_regs, u16 num_avail) ++{ ++ u32 host_regs_val = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_val, num_avail), ++ host_regs); ++} ++ ++static u16 get_num_proc(u8 __iomem *host_regs) ++{ ++ return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET)); ++} ++ ++int hailo_vdma_launch_transfer( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_channel *channel, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ u8 buffers_count, ++ struct hailo_vdma_mapped_transfer_buffer *buffers, ++ bool should_bind, ++ enum hailo_vdma_interrupts_domain first_interrupts_domain, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug) ++{ ++ int ret = -EFAULT; ++ u32 total_descs = 0; ++ u32 first_desc = starting_desc; ++ u32 last_desc = U32_MAX; ++ u16 new_num_avail = 0; ++ struct hailo_ongoing_transfer ongoing_transfer = {0}; ++ u8 i = 0; ++ ++ channel->state.desc_count_mask = (desc_list->desc_count - 1); ++ ++ if (NULL == channel->last_desc_list) { ++ // First transfer on this active channel, store desc list. ++ channel->last_desc_list = desc_list; ++ } else if (desc_list != channel->last_desc_list) { ++ // Shouldn't happen, desc list may change only after channel deactivation. ++ pr_err("Inconsistent desc list given to channel %d\n", channel->index); ++ return -EINVAL; ++ } ++ ++ ret = validate_channel_state(channel); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (channel->state.num_avail != (u16)starting_desc) { ++ pr_err("Channel %d state out of sync. num available is %d, expected %d\n", ++ channel->index, channel->state.num_avail, (u16)starting_desc); ++ return -EFAULT; ++ } ++ ++ if (buffers_count > HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER) { ++ pr_err("Too many buffers %u for single transfer\n", buffers_count); ++ return -EINVAL; ++ } ++ ++ BUILD_BUG_ON_MSG((HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER + 1) != ARRAY_SIZE(ongoing_transfer.dirty_descs), ++ "Unexpected amount of dirty descriptors"); ++ ongoing_transfer.dirty_descs_count = buffers_count + 1; ++ ongoing_transfer.dirty_descs[0] = (u16)starting_desc; ++ ++ for (i = 0; i < buffers_count; i++) { ++ ret = hailo_vdma_program_descriptors_list(vdma_hw, desc_list, ++ starting_desc, &buffers[i], should_bind, channel->index, ++ (i == (buffers_count - 1) ? last_desc_interrupts : HAILO_VDMA_INTERRUPTS_DOMAIN_NONE), ++ is_debug); ++ ++ total_descs += ret; ++ last_desc = (starting_desc + ret - 1) % desc_list->desc_count; ++ starting_desc = (starting_desc + ret) % desc_list->desc_count; ++ ++ ongoing_transfer.dirty_descs[i+1] = (u16)last_desc; ++ ongoing_transfer.buffers[i] = buffers[i]; ++ } ++ ongoing_transfer.buffers_count = buffers_count; ++ ++ desc_list->desc_list[first_desc].PageSize_DescControl |= ++ get_interrupts_bitmask(vdma_hw, first_interrupts_domain, is_debug); ++ ++ ongoing_transfer.last_desc = (u16)last_desc; ++ ongoing_transfer.is_debug = is_debug; ++ ret = ongoing_transfer_push(channel, &ongoing_transfer); ++ if (ret < 0) { ++ pr_err("Failed push ongoing transfer to channel %d\n", channel->index); ++ return ret; ++ } ++ ++ new_num_avail = (u16)((last_desc + 1) % desc_list->desc_count); ++ channel->state.num_avail = new_num_avail; ++ set_num_avail(channel->host_regs, new_num_avail); ++ ++ return (int)total_descs; ++} ++ ++static void hailo_vdma_push_timestamp(struct hailo_vdma_channel *channel) ++{ ++ struct hailo_channel_interrupt_timestamp_list *timestamp_list = &channel->timestamp_list; ++ const u16 num_proc = get_num_proc(channel->host_regs); ++ if (TIMESTAMPS_CIRC_SPACE(*timestamp_list) != 0) { ++ timestamp_list->timestamps[timestamp_list->head].timestamp_ns = ktime_get_ns(); ++ timestamp_list->timestamps[timestamp_list->head].desc_num_processed = num_proc; ++ timestamp_list->head = (timestamp_list->head + 1) & CHANNEL_IRQ_TIMESTAMPS_SIZE_MASK; ++ } ++} ++ ++// Returns false if there are no items ++static bool hailo_vdma_pop_timestamp(struct hailo_channel_interrupt_timestamp_list *timestamp_list, ++ struct hailo_channel_interrupt_timestamp *out_timestamp) ++{ ++ if (0 == TIMESTAMPS_CIRC_CNT(*timestamp_list)) { ++ return false; ++ } ++ ++ *out_timestamp = timestamp_list->timestamps[timestamp_list->tail]; ++ timestamp_list->tail = (timestamp_list->tail+1) & CHANNEL_IRQ_TIMESTAMPS_SIZE_MASK; ++ return true; ++} ++ ++static void hailo_vdma_pop_timestamps_to_response(struct hailo_vdma_channel *channel, ++ struct hailo_vdma_interrupts_read_timestamp_params *result) ++{ ++ const u32 max_timestamps = ARRAY_SIZE(result->timestamps); ++ u32 i = 0; ++ ++ while (hailo_vdma_pop_timestamp(&channel->timestamp_list, &result->timestamps[i]) && ++ (i < max_timestamps)) { ++ // Although the hw_num_processed should be a number between 0 and ++ // desc_count-1, if desc_count < 0x10000 (the maximum desc size), ++ // the actual hw_num_processed is a number between 1 and desc_count. ++ // Therefore the value can be desc_count, in this case we change it to ++ // zero. ++ result->timestamps[i].desc_num_processed = result->timestamps[i].desc_num_processed & ++ channel->state.desc_count_mask; ++ i++; ++ } ++ ++ result->timestamps_count = i; ++} ++ ++static void channel_state_init(struct hailo_vdma_channel_state *state) ++{ ++ state->num_avail = state->num_proc = 0; ++ ++ // Special value used when the channel is not activate. ++ state->desc_count_mask = U32_MAX; ++} ++ ++static u8 __iomem *get_channel_regs(u8 __iomem *regs_base, u8 channel_index, bool is_host_side, u32 src_channels_bitmask) ++{ ++ // Check if getting host side regs or device side ++ u8 __iomem *channel_regs_base = regs_base + CHANNEL_BASE_OFFSET(channel_index); ++ if (is_host_side) { ++ return hailo_test_bit(channel_index, &src_channels_bitmask) ? channel_regs_base : ++ (channel_regs_base + CHANNEL_DEST_REGS_OFFSET); ++ } else { ++ return hailo_test_bit(channel_index, &src_channels_bitmask) ? (channel_regs_base + CHANNEL_DEST_REGS_OFFSET) : ++ channel_regs_base; ++ } ++} ++ ++void hailo_vdma_engine_init(struct hailo_vdma_engine *engine, u8 engine_index, ++ const struct hailo_resource *channel_registers, u32 src_channels_bitmask) ++{ ++ u8 channel_index = 0; ++ struct hailo_vdma_channel *channel; ++ ++ engine->index = engine_index; ++ engine->enabled_channels = 0x0; ++ engine->interrupted_channels = 0x0; ++ ++ for_each_vdma_channel(engine, channel, channel_index) { ++ u8 __iomem *regs_base = (u8 __iomem *)channel_registers->address; ++ channel->host_regs = get_channel_regs(regs_base, channel_index, true, src_channels_bitmask); ++ channel->device_regs = get_channel_regs(regs_base, channel_index, false, src_channels_bitmask); ++ channel->index = channel_index; ++ channel->timestamp_measure_enabled = false; ++ ++ channel_state_init(&channel->state); ++ channel->last_desc_list = NULL; ++ ++ channel->ongoing_transfers.head = 0; ++ channel->ongoing_transfers.tail = 0; ++ } ++} ++ ++/** ++ * Enables the given channels bitmap in the given engine. Allows launching transfer ++ * and reading interrupts from the channels. ++ * ++ * @param engine - dma engine. ++ * @param bitmap - channels bitmap to enable. ++ * @param measure_timestamp - if set, allow interrupts timestamp measure. ++ */ ++void hailo_vdma_engine_enable_channels(struct hailo_vdma_engine *engine, u32 bitmap, ++ bool measure_timestamp) ++{ ++ struct hailo_vdma_channel *channel = NULL; ++ u8 channel_index = 0; ++ ++ for_each_vdma_channel(engine, channel, channel_index) { ++ if (hailo_test_bit(channel_index, &bitmap)) { ++ channel->timestamp_measure_enabled = measure_timestamp; ++ channel->timestamp_list.head = channel->timestamp_list.tail = 0; ++ } ++ } ++ ++ engine->enabled_channels |= bitmap; ++} ++ ++/** ++ * Disables the given channels bitmap in the given engine. ++ * ++ * @param engine - dma engine. ++ * @param bitmap - channels bitmap to enable. ++ * @param measure_timestamp - if set, allow interrupts timestamp measure. ++ */ ++void hailo_vdma_engine_disable_channels(struct hailo_vdma_engine *engine, u32 bitmap) ++{ ++ struct hailo_vdma_channel *channel = NULL; ++ u8 channel_index = 0; ++ ++ engine->enabled_channels &= ~bitmap; ++ ++ for_each_vdma_channel(engine, channel, channel_index) { ++ channel_state_init(&channel->state); ++ ++ while (ONGOING_TRANSFERS_CIRC_CNT(channel->ongoing_transfers) > 0) { ++ struct hailo_ongoing_transfer transfer; ++ ongoing_transfer_pop(channel, &transfer); ++ ++ if (channel->last_desc_list == NULL) { ++ pr_err("Channel %d has ongoing transfers but no desc list\n", channel->index); ++ continue; ++ } ++ ++ clear_dirty_descs(channel, &transfer); ++ } ++ ++ channel->last_desc_list = NULL; ++ } ++} ++ ++void hailo_vdma_engine_push_timestamps(struct hailo_vdma_engine *engine, u32 bitmap) ++{ ++ struct hailo_vdma_channel *channel = NULL; ++ u8 channel_index = 0; ++ ++ for_each_vdma_channel(engine, channel, channel_index) { ++ if (unlikely(hailo_test_bit(channel_index, &bitmap) && ++ channel->timestamp_measure_enabled)) { ++ hailo_vdma_push_timestamp(channel); ++ } ++ } ++} ++ ++int hailo_vdma_engine_read_timestamps(struct hailo_vdma_engine *engine, ++ struct hailo_vdma_interrupts_read_timestamp_params *params) ++{ ++ struct hailo_vdma_channel *channel = NULL; ++ ++ if (params->channel_index >= MAX_VDMA_CHANNELS_PER_ENGINE) { ++ return -EINVAL; ++ } ++ ++ channel = &engine->channels[params->channel_index]; ++ hailo_vdma_pop_timestamps_to_response(channel, params); ++ return 0; ++} ++ ++void hailo_vdma_engine_clear_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap) ++{ ++ engine->interrupted_channels &= ~bitmap; ++} ++ ++void hailo_vdma_engine_set_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap) ++{ ++ engine->interrupted_channels |= bitmap; ++} ++ ++static void fill_channel_irq_data(struct hailo_vdma_interrupts_channel_data *irq_data, ++ struct hailo_vdma_engine *engine, struct hailo_vdma_channel *channel, u8 transfers_completed, ++ bool validation_success) ++{ ++ u8 host_control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(channel->host_regs)); ++ u8 device_control = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(channel->device_regs)); ++ ++ irq_data->engine_index = engine->index; ++ irq_data->channel_index = channel->index; ++ ++ irq_data->is_active = channel_control_reg_is_active(host_control) && ++ channel_control_reg_is_active(device_control); ++ ++ irq_data->transfers_completed = transfers_completed; ++ irq_data->host_error = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, 0, ioread32(channel->host_regs + CHANNEL_ERROR_OFFSET)); ++ irq_data->device_error = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, 0, ioread32(channel->device_regs + CHANNEL_ERROR_OFFSET)); ++ irq_data->validation_success = validation_success; ++} ++ ++static bool is_desc_between(u16 begin, u16 end, u16 desc) ++{ ++ if (begin == end) { ++ // There is nothing between ++ return false; ++ } ++ if (begin < end) { ++ // desc needs to be in [begin, end) ++ return (begin <= desc) && (desc < end); ++ } ++ else { ++ // desc needs to be in [0, end) or [begin, m_descs.size()-1] ++ return (desc < end) || (begin <= desc); ++ } ++} ++ ++static bool is_transfer_complete(struct hailo_vdma_channel *channel, ++ struct hailo_ongoing_transfer *transfer, u16 hw_num_proc) ++{ ++ if (channel->state.num_avail == hw_num_proc) { ++ return true; ++ } ++ ++ return is_desc_between(channel->state.num_proc, hw_num_proc, transfer->last_desc); ++} ++ ++int hailo_vdma_engine_fill_irq_data(struct hailo_vdma_interrupts_wait_params *irq_data, ++ struct hailo_vdma_engine *engine, u32 irq_channels_bitmap, ++ transfer_done_cb_t transfer_done, void *transfer_done_opaque) ++{ ++ struct hailo_vdma_channel *channel = NULL; ++ u8 channel_index = 0; ++ bool validation_success = true; ++ ++ for_each_vdma_channel(engine, channel, channel_index) { ++ u8 transfers_completed = 0; ++ u16 hw_num_proc = U16_MAX; ++ ++ BUILD_BUG_ON_MSG(HAILO_VDMA_MAX_ONGOING_TRANSFERS >= U8_MAX, ++ "HAILO_VDMA_MAX_ONGOING_TRANSFERS must be less than U8_MAX to use transfers_completed as u8"); ++ ++ if (!hailo_test_bit(channel->index, &irq_channels_bitmap)) { ++ continue; ++ } ++ ++ if (channel->last_desc_list == NULL) { ++ // Channel not active or no transfer, skipping. ++ continue; ++ } ++ ++ if (irq_data->channels_count >= ARRAY_SIZE(irq_data->irq_data)) { ++ return -EINVAL; ++ } ++ ++ // Although the hw_num_processed should be a number between 0 and ++ // desc_count-1, if desc_count < 0x10000 (the maximum desc size), ++ // the actual hw_num_processed is a number between 1 and desc_count. ++ // Therefore the value can be desc_count, in this case we change it to ++ // zero. ++ hw_num_proc = get_num_proc(channel->host_regs) & channel->state.desc_count_mask; ++ ++ while (ONGOING_TRANSFERS_CIRC_CNT(channel->ongoing_transfers) > 0) { ++ struct hailo_ongoing_transfer *cur_transfer = ++ &channel->ongoing_transfers.transfers[channel->ongoing_transfers.tail]; ++ if (!is_transfer_complete(channel, cur_transfer, hw_num_proc)) { ++ break; ++ } ++ ++ if (cur_transfer->is_debug && ++ !validate_last_desc_status(channel, cur_transfer)) { ++ validation_success = false; ++ } ++ ++ clear_dirty_descs(channel, cur_transfer); ++ transfer_done(cur_transfer, transfer_done_opaque); ++ channel->state.num_proc = (u16)((cur_transfer->last_desc + 1) & channel->state.desc_count_mask); ++ ++ ongoing_transfer_pop(channel, NULL); ++ transfers_completed++; ++ } ++ ++ fill_channel_irq_data(&irq_data->irq_data[irq_data->channels_count], ++ engine, channel, transfers_completed, validation_success); ++ irq_data->channels_count++; ++ } ++ ++ return 0; ++} ++ ++// For all these functions - best way to optimize might be to not call the function when need to pause and then abort, ++// Rather read value once and maybe save ++// This function reads and writes the register - should try to make more optimized in future ++static void start_vdma_control_register(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_START_RESUME), host_regs); ++} ++ ++static void hailo_vdma_channel_pause(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_START_PAUSE), host_regs); ++} ++ ++// This function reads and writes the register - should try to make more optimized in future ++static void hailo_vdma_channel_abort(u8 __iomem *host_regs) ++{ ++ u32 host_regs_value = ioread32(host_regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, host_regs_value, ++ VDMA_CHANNEL_CONTROL_ABORT), host_regs); ++} ++ ++int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, ++ uint8_t data_id) ++{ ++ u16 dma_address_l = 0; ++ u32 dma_address_h = 0; ++ u32 desc_depth_data_id = 0; ++ ++ if (((desc_dma_address & 0xFFFF) != 0) || ++ (desc_depth > DESCRIPTOR_LIST_MAX_DEPTH)) { ++ return -EINVAL; ++ } ++ ++ // According to spec, depth 16 is equivalent to depth 0. ++ if (DESCRIPTOR_LIST_MAX_DEPTH == desc_depth) { ++ desc_depth = 0; ++ } ++ ++ // Stop old channel state ++ hailo_vdma_stop_channel(host_regs); ++ ++ // Configure address, depth and id ++ dma_address_l = (uint16_t)((desc_dma_address >> 16) & 0xFFFF); ++ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, (VDMA_CHANNEL__ADDRESS_L_OFFSET - ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET) * BITS_IN_BYTE, ioread32(host_regs + ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET), dma_address_l), host_regs + VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET); ++ ++ dma_address_h = (uint32_t)(desc_dma_address >> 32); ++ iowrite32(dma_address_h, host_regs + VDMA_CHANNEL__ADDRESS_H_OFFSET); ++ ++ desc_depth_data_id = (uint32_t)(desc_depth << VDMA_CHANNEL_DESC_DEPTH_SHIFT) | ++ (data_id << VDMA_CHANNEL_DATA_ID_SHIFT); ++ iowrite32(desc_depth_data_id, host_regs); ++ ++ start_vdma_control_register(host_regs); ++ ++ return 0; ++} ++ ++static bool hailo_vdma_channel_is_idle(u8 __iomem *host_regs, size_t host_side_max_desc_count) ++{ ++ // Num processed and ongoing are next to each other in the memory. ++ // Reading them both in order to save BAR reads. ++ u32 host_side_num_processed_ongoing = ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET); ++ u16 host_side_num_processed = (host_side_num_processed_ongoing & VDMA_CHANNEL_NUM_PROCESSED_MASK); ++ u16 host_side_num_ongoing = (host_side_num_processed_ongoing >> VDMA_CHANNEL_NUM_PROCESSED_WIDTH) & ++ VDMA_CHANNEL_NUM_ONGOING_MASK; ++ ++ if ((host_side_num_processed % host_side_max_desc_count) == (host_side_num_ongoing % host_side_max_desc_count)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static int hailo_vdma_wait_until_channel_idle(u8 __iomem *host_regs) ++{ ++ bool is_idle = false; ++ uint32_t check_counter = 0; ++ ++ u8 depth = (uint8_t)(READ_BITS_AT_OFFSET(VDMA_CHANNEL_DESC_DEPTH_WIDTH, VDMA_CHANNEL_DESC_DEPTH_SHIFT, ++ ioread32(host_regs))); ++ size_t host_side_max_desc_count = (size_t)(1 << depth); ++ ++ for (check_counter = 0; check_counter < VDMA_CHANNEL__MAX_CHECKS_CHANNEL_IS_IDLE; check_counter++) { ++ is_idle = hailo_vdma_channel_is_idle(host_regs, host_side_max_desc_count); ++ if (is_idle) { ++ return 0; ++ } ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++void hailo_vdma_stop_channel(u8 __iomem *host_regs) ++{ ++ int err = 0; ++ u8 host_side_channel_regs = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(host_regs)); ++ ++ if ((host_side_channel_regs & VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK) == VDMA_CHANNEL_CONTROL_ABORT_PAUSE) { ++ // The channel is aborted (we set the channel to VDMA_CHANNEL_CONTROL_ABORT_PAUSE at the end of this function) ++ return; ++ } ++ ++ // Pause the channel ++ // The channel is paused to allow for "all transfers from fetched descriptors..." to be "...completed" ++ // (from PLDA PCIe refernce manual, "9.2.5 Starting a Channel and Transferring Data") ++ hailo_vdma_channel_pause(host_regs); ++ ++ // Even if channel is stuck and not idle, force abort and return error in the end ++ err = hailo_vdma_wait_until_channel_idle(host_regs); ++ // Success oriented - if error occured print error but still abort channel ++ if (err < 0) { ++ pr_err("Timeout occured while waiting for channel to become idle\n"); ++ } ++ ++ // Abort the channel (even of hailo_vdma_wait_until_channel_idle function fails) ++ hailo_vdma_channel_abort(host_regs); ++} ++ ++bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel) ++{ ++ return is_input_channel ? hailo_test_bit(channel_index, &src_channels_bitmask) : ++ (!hailo_test_bit(channel_index, &src_channels_bitmask)); ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/common/vdma_common.h b/drivers/media/pci/hailo/common/vdma_common.h +new file mode 100644 +index 000000000000..0d84ac6d31bd +--- /dev/null ++++ b/drivers/media/pci/hailo/common/vdma_common.h +@@ -0,0 +1,257 @@ ++// SPDX-License-Identifier: MIT ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_COMMON_VDMA_COMMON_H_ ++#define _HAILO_COMMON_VDMA_COMMON_H_ ++ ++#include "hailo_resource.h" ++#include "utils.h" ++ ++#include ++#include ++#include ++ ++#define VDMA_DESCRIPTOR_LIST_ALIGN (1 << 16) ++#define INVALID_VDMA_ADDRESS (0) ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++struct hailo_vdma_descriptor { ++ u32 PageSize_DescControl; ++ u32 AddrL_rsvd_DataID; ++ u32 AddrH; ++ u32 RemainingPageSize_Status; ++}; ++ ++struct hailo_vdma_descriptors_list { ++ struct hailo_vdma_descriptor *desc_list; ++ u32 desc_count; // Must be power of 2 if is_circular is set. ++ u16 desc_page_size; ++ bool is_circular; ++}; ++ ++struct hailo_channel_interrupt_timestamp_list { ++ int head; ++ int tail; ++ struct hailo_channel_interrupt_timestamp timestamps[CHANNEL_IRQ_TIMESTAMPS_SIZE]; ++}; ++ ++ ++// For each buffers in transfer, the last descriptor will be programmed with ++// the residue size. In addition, if configured, the first descriptor (in ++// all transfer) may be programmed with interrupts. ++#define MAX_DIRTY_DESCRIPTORS_PER_TRANSFER \ ++ (HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER + 1) ++ ++struct hailo_vdma_mapped_transfer_buffer { ++ struct sg_table *sg_table; ++ u32 size; ++ u32 offset; ++ void *opaque; // Drivers can set any opaque data here. ++}; ++ ++struct hailo_ongoing_transfer { ++ uint16_t last_desc; ++ ++ u8 buffers_count; ++ struct hailo_vdma_mapped_transfer_buffer buffers[HAILO_MAX_BUFFERS_PER_SINGLE_TRANSFER]; ++ ++ // Contains all descriptors that were programmed with non-default values ++ // for the transfer (by non-default we mean - different size or different ++ // interrupts domain). ++ uint8_t dirty_descs_count; ++ uint16_t dirty_descs[MAX_DIRTY_DESCRIPTORS_PER_TRANSFER]; ++ ++ // If set, validate descriptors status on transfer completion. ++ bool is_debug; ++}; ++ ++struct hailo_ongoing_transfers_list { ++ unsigned long head; ++ unsigned long tail; ++ struct hailo_ongoing_transfer transfers[HAILO_VDMA_MAX_ONGOING_TRANSFERS]; ++}; ++ ++struct hailo_vdma_channel_state { ++ // vdma channel counters. num_avail should be synchronized with the hw ++ // num_avail value. num_proc is the last num proc updated when the user ++ // reads interrupts. ++ u16 num_avail; ++ u16 num_proc; ++ ++ // Mask of the num-avail/num-proc counters. ++ u32 desc_count_mask; ++}; ++ ++struct hailo_vdma_channel { ++ u8 index; ++ ++ u8 __iomem *host_regs; ++ u8 __iomem *device_regs; ++ ++ // Last descriptors list attached to the channel. When it changes, ++ // assumes that the channel got reset. ++ struct hailo_vdma_descriptors_list *last_desc_list; ++ ++ struct hailo_vdma_channel_state state; ++ struct hailo_ongoing_transfers_list ongoing_transfers; ++ ++ bool timestamp_measure_enabled; ++ struct hailo_channel_interrupt_timestamp_list timestamp_list; ++}; ++ ++struct hailo_vdma_engine { ++ u8 index; ++ u32 enabled_channels; ++ u32 interrupted_channels; ++ struct hailo_vdma_channel channels[MAX_VDMA_CHANNELS_PER_ENGINE]; ++}; ++ ++struct hailo_vdma_hw_ops { ++ // Accepts some dma_addr_t mapped to the device and encodes it using ++ // hw specific encode. returns INVALID_VDMA_ADDRESS on failure. ++ u64 (*encode_desc_dma_address)(dma_addr_t dma_address, u8 channel_id); ++}; ++ ++struct hailo_vdma_hw { ++ struct hailo_vdma_hw_ops hw_ops; ++ ++ // The data_id code of ddr addresses. ++ u8 ddr_data_id; ++ ++ // Bitmask needed to set on each descriptor to enable interrupts (either host/device). ++ unsigned long host_interrupts_bitmask; ++ unsigned long device_interrupts_bitmask; ++ ++ // Bitmask for each vdma hw, which channels are src side by index (on pcie/dram - 0x0000FFFF, pci ep - 0xFFFF0000) ++ u32 src_channels_bitmask; ++}; ++ ++#define _for_each_element_array(array, size, element, index) \ ++ for (index = 0, element = &array[index]; index < size; index++, element = &array[index]) ++ ++#define for_each_vdma_channel(engine, channel, channel_index) \ ++ _for_each_element_array(engine->channels, MAX_VDMA_CHANNELS_PER_ENGINE, \ ++ channel, channel_index) ++ ++void hailo_vdma_program_descriptor(struct hailo_vdma_descriptor *descriptor, u64 dma_address, size_t page_size, ++ u8 data_id); ++ ++/** ++ * Program the given descriptors list to map the given buffer. ++ * ++ * @param vdma_hw vdma hw object ++ * @param desc_list descriptors list object to program ++ * @param starting_desc index of the first descriptor to program. If the list ++ * is circular, this function may wrap around the list. ++ * @param buffer buffer to program to the descriptors list. ++ * @param should_bind If false, assumes the buffer was already bound to the ++ * desc list. Used for optimization. ++ * @param channel_index channel index of the channel attached. ++ * @param last_desc_interrupts - interrupts settings on last descriptor. ++ * @param is_debug program descriptors for debug run. ++ * ++ * @return On success - the amount of descriptors programmed, negative value on error. ++ */ ++int hailo_vdma_program_descriptors_list( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ struct hailo_vdma_mapped_transfer_buffer *buffer, ++ bool should_bind, ++ u8 channel_index, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug); ++ ++/** ++ * Launch a transfer on some vdma channel. Includes: ++ * 1. Binding the transfer buffers to the descriptors list. ++ * 2. Program the descriptors list. ++ * 3. Increase num available ++ * ++ * @param vdma_hw vdma hw object ++ * @param channel vdma channel object. ++ * @param desc_list descriptors list object to program. ++ * @param starting_desc index of the first descriptor to program. ++ * @param buffers_count amount of transfer mapped buffers to program. ++ * @param buffers array of buffers to program to the descriptors list. ++ * @param should_bind whether to bind the buffer to the descriptors list. ++ * @param first_interrupts_domain - interrupts settings on first descriptor. ++ * @param last_desc_interrupts - interrupts settings on last descriptor. ++ * @param is_debug program descriptors for debug run, adds some overhead (for ++ * example, hw will write desc complete status). ++ * ++ * @return On success - the amount of descriptors programmed, negative value on error. ++ */ ++int hailo_vdma_launch_transfer( ++ struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_channel *channel, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 starting_desc, ++ u8 buffers_count, ++ struct hailo_vdma_mapped_transfer_buffer *buffers, ++ bool should_bind, ++ enum hailo_vdma_interrupts_domain first_interrupts_domain, ++ enum hailo_vdma_interrupts_domain last_desc_interrupts, ++ bool is_debug); ++ ++void hailo_vdma_engine_init(struct hailo_vdma_engine *engine, u8 engine_index, ++ const struct hailo_resource *channel_registers, u32 src_channels_bitmask); ++ ++void hailo_vdma_engine_enable_channels(struct hailo_vdma_engine *engine, u32 bitmap, ++ bool measure_timestamp); ++ ++void hailo_vdma_engine_disable_channels(struct hailo_vdma_engine *engine, u32 bitmap); ++ ++void hailo_vdma_engine_push_timestamps(struct hailo_vdma_engine *engine, u32 bitmap); ++int hailo_vdma_engine_read_timestamps(struct hailo_vdma_engine *engine, ++ struct hailo_vdma_interrupts_read_timestamp_params *params); ++ ++static inline bool hailo_vdma_engine_got_interrupt(struct hailo_vdma_engine *engine, ++ u32 channels_bitmap) ++{ ++ // Reading interrupts without lock is ok (needed only for writes) ++ const bool any_interrupt = (0 != (channels_bitmap & engine->interrupted_channels)); ++ const bool any_disabled = (channels_bitmap != (channels_bitmap & engine->enabled_channels)); ++ return (any_disabled || any_interrupt); ++} ++ ++// Set/Clear/Read channels interrupts, must called under some lock (driver specific) ++void hailo_vdma_engine_clear_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap); ++void hailo_vdma_engine_set_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap); ++ ++static inline u32 hailo_vdma_engine_read_interrupts(struct hailo_vdma_engine *engine, ++ u32 requested_bitmap) ++{ ++ // Interrupts only for channels that are requested and enabled. ++ u32 irq_channels_bitmap = requested_bitmap & ++ engine->enabled_channels & ++ engine->interrupted_channels; ++ engine->interrupted_channels &= ~irq_channels_bitmap; ++ ++ return irq_channels_bitmap; ++} ++ ++typedef void(*transfer_done_cb_t)(struct hailo_ongoing_transfer *transfer, void *opaque); ++ ++// Assuming irq_data->channels_count contains the amount of channels already ++// written (used for multiple engines). ++int hailo_vdma_engine_fill_irq_data(struct hailo_vdma_interrupts_wait_params *irq_data, ++ struct hailo_vdma_engine *engine, u32 irq_channels_bitmap, ++ transfer_done_cb_t transfer_done, void *transfer_done_opaque); ++ ++int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, uint8_t data_id); ++ ++void hailo_vdma_stop_channel(u8 __iomem *host_regs); ++ ++bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* _HAILO_COMMON_VDMA_COMMON_H_ */ +diff --git a/drivers/media/pci/hailo/include/hailo_pcie_version.h b/drivers/media/pci/hailo/include/hailo_pcie_version.h +new file mode 100755 +index 000000000000..936bd7d4a477 +--- /dev/null ++++ b/drivers/media/pci/hailo/include/hailo_pcie_version.h +@@ -0,0 +1,14 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCIE_VERSION_H_ ++#define _HAILO_PCIE_VERSION_H_ ++ ++#include ++#include "../common/hailo_pcie_version.h" ++ ++#define HAILO_DRV_VER __stringify(HAILO_DRV_VER_MAJOR) "." __stringify(HAILO_DRV_VER_MINOR) "." __stringify(HAILO_DRV_VER_REVISION) ++ ++#endif /* _HAILO_PCIE_VERSION_H_ */ +diff --git a/drivers/media/pci/hailo/src/fops.c b/drivers/media/pci/hailo/src/fops.c +new file mode 100644 +index 000000000000..6b455774d973 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/fops.c +@@ -0,0 +1,762 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) ++#include ++#endif ++ ++#include "utils.h" ++#include "fops.h" ++#include "vdma_common.h" ++#include "utils/logs.h" ++#include "vdma/memory.h" ++#include "vdma/ioctl.h" ++#include "utils/compact.h" ++#include "pci_soc_ioctl.h" ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 13, 0 ) ++#define wait_queue_t wait_queue_entry_t ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 15, 0 ) ++#define ACCESS_ONCE READ_ONCE ++#endif ++ ++#ifndef VM_RESERVED ++ #define VMEM_FLAGS (VM_IO | VM_DONTEXPAND | VM_DONTDUMP) ++#else ++ #define VMEM_FLAGS (VM_IO | VM_RESERVED) ++#endif ++ ++#define IS_PO2_ALIGNED(size, alignment) (!(size & (alignment-1))) ++ ++// On pcie driver there is only one dma engine ++#define DEFAULT_VDMA_ENGINE_INDEX (0) ++ ++#if !defined(HAILO_EMULATOR) ++#define DEFAULT_SHUTDOWN_TIMEOUT_MS (5) ++#else /* !defined(HAILO_EMULATOR) */ ++#define DEFAULT_SHUTDOWN_TIMEOUT_MS (1000) ++#endif /* !defined(HAILO_EMULATOR) */ ++ ++static long hailo_add_notification_wait(struct hailo_pcie_board *board, struct file *filp); ++ ++static struct hailo_file_context *create_file_context(struct hailo_pcie_board *board, struct file *filp) ++{ ++ struct hailo_file_context *context = kzalloc(sizeof(*context), GFP_KERNEL); ++ if (!context) { ++ hailo_err(board, "Failed to alloc file context (required size %zu)\n", sizeof(*context)); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ context->filp = filp; ++ hailo_vdma_file_context_init(&context->vdma_context); ++ list_add(&context->open_files_list, &board->open_files_list); ++ context->is_valid = true; ++ return context; ++} ++ ++static void release_file_context(struct hailo_file_context *context) ++{ ++ context->is_valid = false; ++ list_del(&context->open_files_list); ++ kfree(context); ++} ++ ++static struct hailo_file_context *find_file_context(struct hailo_pcie_board *board, struct file *filp) ++{ ++ struct hailo_file_context *cur = NULL; ++ list_for_each_entry(cur, &board->open_files_list, open_files_list) { ++ if (cur->filp == filp) { ++ return cur; ++ } ++ } ++ return NULL; ++} ++ ++int hailo_pcie_fops_open(struct inode *inode, struct file *filp) ++{ ++ u32 major = MAJOR(inode->i_rdev); ++ u32 minor = MINOR(inode->i_rdev); ++ struct hailo_pcie_board *pBoard; ++ int err = 0; ++ pci_power_t previous_power_state = PCI_UNKNOWN; ++ bool interrupts_enabled_by_filp = false; ++ struct hailo_file_context *context = NULL; ++ ++ pr_debug(DRIVER_NAME ": (%d: %d-%d): fops_open\n", current->tgid, major, minor); ++ ++ // allow multiple processes to open a device, count references in hailo_pcie_get_board_index. ++ if (!(pBoard = hailo_pcie_get_board_index(minor))) { ++ pr_err(DRIVER_NAME ": fops_open: PCIe board not found for /dev/hailo%d node.\n", minor); ++ err = -ENODEV; ++ goto l_exit; ++ } ++ ++ filp->private_data = pBoard; ++ ++ if (down_interruptible(&pBoard->mutex)) { ++ hailo_err(pBoard, "fops_open down_interruptible fail tgid:%d\n", current->tgid); ++ err = -ERESTARTSYS; ++ goto l_decrease_ref_count; ++ } ++ ++ context = create_file_context(pBoard, filp); ++ if (IS_ERR(context)) { ++ err = PTR_ERR(context); ++ goto l_release_mutex; ++ } ++ ++ previous_power_state = pBoard->pDev->current_state; ++ if (PCI_D0 != previous_power_state) { ++ hailo_info(pBoard, "Waking up board"); ++ err = pci_set_power_state(pBoard->pDev, PCI_D0); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed waking up board %d", err); ++ goto l_free_context; ++ } ++ } ++ ++ if (!hailo_pcie_is_device_connected(&pBoard->pcie_resources)) { ++ hailo_err(pBoard, "Device disconnected while opening device\n"); ++ err = -ENXIO; ++ goto l_revert_power_state; ++ } ++ ++ // enable interrupts ++ if (!pBoard->interrupts_enabled) { ++ err = hailo_enable_interrupts(pBoard); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed Enabling interrupts %d\n", err); ++ goto l_revert_power_state; ++ } ++ interrupts_enabled_by_filp = true; ++ } ++ ++ err = hailo_add_notification_wait(pBoard, filp); ++ if (err < 0) { ++ goto l_release_irq; ++ } ++ ++ hailo_dbg(pBoard, "(%d: %d-%d): fops_open: SUCCESS on /dev/hailo%d\n", current->tgid, ++ major, minor, minor); ++ ++ up(&pBoard->mutex); ++ return 0; ++ ++l_release_irq: ++ if (interrupts_enabled_by_filp) { ++ hailo_disable_interrupts(pBoard); ++ } ++ ++l_revert_power_state: ++ if (pBoard->pDev->current_state != previous_power_state) { ++ if (pci_set_power_state(pBoard->pDev, previous_power_state) < 0) { ++ hailo_err(pBoard, "Failed setting power state back to %d\n", (int)previous_power_state); ++ } ++ } ++l_free_context: ++ release_file_context(context); ++l_release_mutex: ++ up(&pBoard->mutex); ++l_decrease_ref_count: ++ atomic_dec(&pBoard->ref_count); ++l_exit: ++ return err; ++} ++ ++int hailo_pcie_driver_down(struct hailo_pcie_board *board) ++{ ++ long completion_result = 0; ++ int err = 0; ++ ++ reinit_completion(&board->driver_down.reset_completed); ++ ++ hailo_pcie_write_firmware_driver_shutdown(&board->pcie_resources); ++ ++ // Wait for response ++ completion_result = ++ wait_for_completion_timeout(&board->driver_down.reset_completed, msecs_to_jiffies(DEFAULT_SHUTDOWN_TIMEOUT_MS)); ++ if (completion_result <= 0) { ++ if (0 == completion_result) { ++ hailo_err(board, "hailo_pcie_driver_down, timeout waiting for shutdown response (timeout_ms=%d)\n", DEFAULT_SHUTDOWN_TIMEOUT_MS); ++ err = -ETIMEDOUT; ++ } else { ++ hailo_info(board, "hailo_pcie_driver_down, wait for completion failed with err=%ld (process was interrupted or killed)\n", ++ completion_result); ++ err = completion_result; ++ } ++ goto l_exit; ++ } ++ ++l_exit: ++ return err; ++} ++ ++int hailo_pcie_fops_release(struct inode *inode, struct file *filp) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)filp->private_data; ++ struct hailo_file_context *context = NULL; ++ ++ u32 major = MAJOR(inode->i_rdev); ++ u32 minor = MINOR(inode->i_rdev); ++ ++ if (board) { ++ hailo_info(board, "(%d: %d-%d): fops_release\n", current->tgid, major, minor); ++ ++ ++ down(&board->mutex); ++ ++ context = find_file_context(board, filp); ++ if (NULL == context) { ++ hailo_err(board, "Invalid driver state, file context does not exist\n"); ++ up(&board->mutex); ++ return -EINVAL; ++ } ++ ++ if (false == context->is_valid) { ++ // File context is invalid, but open. It's OK to continue finalize and release it. ++ hailo_err(board, "Invalid file context\n"); ++ } ++ ++ hailo_pcie_clear_notification_wait_list(board, filp); ++ ++ if (filp == board->vdma.used_by_filp) { ++ if (hailo_pcie_driver_down(board)) { ++ hailo_err(board, "Failed sending FW shutdown event"); ++ } ++ } ++ ++ hailo_vdma_file_context_finalize(&context->vdma_context, &board->vdma, filp); ++ release_file_context(context); ++ ++ if (atomic_dec_and_test(&board->ref_count)) { ++ // Disable interrupts ++ hailo_disable_interrupts(board); ++ ++ if (power_mode_enabled()) { ++ if (board->pDev && pci_set_power_state(board->pDev, PCI_D3hot) < 0) { ++ hailo_err(board, "Failed setting power state to D3hot"); ++ } ++ } ++ ++ // deallocate board if already removed ++ if (!board->pDev) { ++ hailo_dbg(board, "fops_release, freed board\n"); ++ up(&board->mutex); ++ kfree(board); ++ board = NULL; ++ } else { ++ hailo_dbg(board, "fops_release, released resources for board\n"); ++ up(&board->mutex); ++ } ++ } else { ++ up(&board->mutex); ++ } ++ ++ hailo_dbg(board, "(%d: %d-%d): fops_release: SUCCESS on /dev/hailo%d\n", current->tgid, ++ major, minor, minor); ++ } ++ ++ return 0; ++} ++ ++static long hailo_memory_transfer_ioctl(struct hailo_pcie_board *board, unsigned long arg) ++{ ++ long err = 0; ++ struct hailo_memory_transfer_params* transfer = &board->memory_transfer_params; ++ ++ hailo_dbg(board, "Start memory transfer ioctl\n"); ++ ++ if (copy_from_user(transfer, (void __user*)arg, sizeof(*transfer))) { ++ hailo_err(board, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ err = hailo_pcie_memory_transfer(&board->pcie_resources, transfer); ++ if (err < 0) { ++ hailo_err(board, "memory transfer failed %ld", err); ++ } ++ ++ if (copy_to_user((void __user*)arg, transfer, sizeof(*transfer))) { ++ hailo_err(board, "copy_to_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ return err; ++} ++ ++static long hailo_read_log_ioctl(struct hailo_pcie_board *pBoard, unsigned long arg) ++{ ++ long err = 0; ++ struct hailo_read_log_params params; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_err(pBoard, "HAILO_READ_LOG, copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ if (0 > (err = hailo_pcie_read_firmware_log(&pBoard->pcie_resources, ¶ms))) { ++ hailo_err(pBoard, "HAILO_READ_LOG, reading from log failed with error: %ld \n", err); ++ return err; ++ } ++ ++ if (copy_to_user((void*)arg, ¶ms, sizeof(params))) { ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void firmware_notification_irq_handler(struct hailo_pcie_board *board) ++{ ++ struct hailo_notification_wait *notif_wait_cursor = NULL; ++ int err = 0; ++ unsigned long irq_saved_flags = 0; ++ ++ spin_lock_irqsave(&board->notification_read_spinlock, irq_saved_flags); ++ err = hailo_pcie_read_firmware_notification(&board->pcie_resources, &board->notification_cache); ++ spin_unlock_irqrestore(&board->notification_read_spinlock, irq_saved_flags); ++ ++ if (err < 0) { ++ hailo_err(board, "Failed reading firmware notification"); ++ } ++ else { ++ rcu_read_lock(); ++ list_for_each_entry_rcu(notif_wait_cursor, &board->notification_wait_list, notification_wait_list) ++ { ++ complete(¬if_wait_cursor->notification_completion); ++ } ++ rcu_read_unlock(); ++ } ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) ++irqreturn_t hailo_irqhandler(int irq, void *dev_id, struct pt_regs *regs) ++#else ++irqreturn_t hailo_irqhandler(int irq, void *dev_id) ++#endif ++{ ++ irqreturn_t return_value = IRQ_NONE; ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)dev_id; ++ bool got_interrupt = false; ++ struct hailo_pcie_interrupt_source irq_source = {0}; ++ ++ hailo_dbg(board, "hailo_irqhandler\n"); ++ ++ while (true) { ++ if (!hailo_pcie_is_device_connected(&board->pcie_resources)) { ++ hailo_err(board, "Device disconnected while handling irq\n"); ++ break; ++ } ++ ++ got_interrupt = hailo_pcie_read_interrupt(&board->pcie_resources, &irq_source); ++ if (!got_interrupt) { ++ break; ++ } ++ ++ return_value = IRQ_HANDLED; ++ ++ // wake fw_control if needed ++ if (irq_source.interrupt_bitmask & FW_CONTROL) { ++ complete(&board->fw_control.completion); ++ } ++ ++ // wake driver_down if needed ++ if (irq_source.interrupt_bitmask & DRIVER_DOWN) { ++ complete(&board->driver_down.reset_completed); ++ } ++ ++ if (irq_source.interrupt_bitmask & FW_NOTIFICATION) { ++ if (!completion_done(&board->fw_loaded_completion)) { ++ // Complete firmware loaded completion ++ complete_all(&board->fw_loaded_completion); ++ } else { ++ firmware_notification_irq_handler(board); ++ } ++ } ++ ++ if (irq_source.interrupt_bitmask & SOC_CONNECT_ACCEPTED) { ++ complete_all(&board->soc_connect_accepted); ++ } ++ ++ if (0 != irq_source.vdma_channels_bitmap) { ++ hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX, ++ irq_source.vdma_channels_bitmap); ++ } ++ } ++ ++ return return_value; ++} ++ ++static long hailo_get_notification_wait_thread(struct hailo_pcie_board *pBoard, struct file *filp, ++ struct hailo_notification_wait **current_waiting_thread) ++{ ++ struct hailo_notification_wait *cursor = NULL; ++ // note: safe to access without rcu because the notification_wait_list is closed only on file release ++ list_for_each_entry(cursor, &pBoard->notification_wait_list, notification_wait_list) ++ { ++ if ((current->tgid == cursor->tgid) && (filp == cursor->filp)) { ++ *current_waiting_thread = cursor; ++ return 0; ++ } ++ } ++ ++ return -EFAULT; ++} ++ ++static long hailo_add_notification_wait(struct hailo_pcie_board *board, struct file *filp) ++{ ++ struct hailo_notification_wait *new_notification_wait = NULL; ++ if (!(new_notification_wait = kmalloc(sizeof(*new_notification_wait), GFP_KERNEL))) { ++ hailo_err(board, "Failed to allocate notification wait structure.\n"); ++ return -ENOMEM; ++ } ++ new_notification_wait->tgid = current->tgid; ++ new_notification_wait->filp = filp; ++ new_notification_wait->is_disabled = false; ++ init_completion(&new_notification_wait->notification_completion); ++ list_add_rcu(&new_notification_wait->notification_wait_list, &board->notification_wait_list); ++ return 0; ++} ++ ++static long hailo_read_notification_ioctl(struct hailo_pcie_board *pBoard, unsigned long arg, struct file *filp, ++ bool* should_up_board_mutex) ++{ ++ long err = 0; ++ struct hailo_notification_wait *current_waiting_thread = NULL; ++ struct hailo_d2h_notification *notification = &pBoard->notification_to_user; ++ unsigned long irq_saved_flags; ++ ++ err = hailo_get_notification_wait_thread(pBoard, filp, ¤t_waiting_thread); ++ if (0 != err) { ++ goto l_exit; ++ } ++ up(&pBoard->mutex); ++ ++ if (0 > (err = wait_for_completion_interruptible(¤t_waiting_thread->notification_completion))) { ++ hailo_info(pBoard, ++ "HAILO_READ_NOTIFICATION - wait_for_completion_interruptible error. err=%ld. tgid=%d (process was interrupted or killed)\n", ++ err, current_waiting_thread->tgid); ++ *should_up_board_mutex = false; ++ goto l_exit; ++ } ++ ++ if (down_interruptible(&pBoard->mutex)) { ++ hailo_info(pBoard, "HAILO_READ_NOTIFICATION - down_interruptible error (process was interrupted or killed)\n"); ++ *should_up_board_mutex = false; ++ err = -ERESTARTSYS; ++ goto l_exit; ++ } ++ ++ // Check if was disabled ++ if (current_waiting_thread->is_disabled) { ++ hailo_info(pBoard, "HAILO_READ_NOTIFICATION, can't find notification wait for tgid=%d\n", current->tgid); ++ err = -EINVAL; ++ goto l_exit; ++ } ++ ++ reinit_completion(¤t_waiting_thread->notification_completion); ++ ++ spin_lock_irqsave(&pBoard->notification_read_spinlock, irq_saved_flags); ++ notification->buffer_len = pBoard->notification_cache.buffer_len; ++ memcpy(notification->buffer, pBoard->notification_cache.buffer, notification->buffer_len); ++ spin_unlock_irqrestore(&pBoard->notification_read_spinlock, irq_saved_flags); ++ ++ if (copy_to_user((void __user*)arg, notification, sizeof(*notification))) { ++ hailo_err(pBoard, "HAILO_READ_NOTIFICATION copy_to_user fail\n"); ++ err = -ENOMEM; ++ goto l_exit; ++ } ++ ++l_exit: ++ return err; ++} ++ ++static long hailo_disable_notification(struct hailo_pcie_board *pBoard, struct file *filp) ++{ ++ struct hailo_notification_wait *cursor = NULL; ++ ++ hailo_info(pBoard, "HAILO_DISABLE_NOTIFICATION: disable notification"); ++ rcu_read_lock(); ++ list_for_each_entry_rcu(cursor, &pBoard->notification_wait_list, notification_wait_list) { ++ if ((current->tgid == cursor->tgid) && (filp == cursor->filp)) { ++ cursor->is_disabled = true; ++ complete(&cursor->notification_completion); ++ break; ++ } ++ } ++ rcu_read_unlock(); ++ ++ return 0; ++} ++ ++static int hailo_fw_control(struct hailo_pcie_board *pBoard, unsigned long arg, bool* should_up_board_mutex) ++{ ++ struct hailo_fw_control *command = &pBoard->fw_control.command; ++ long completion_result = 0; ++ int err = 0; ++ ++ up(&pBoard->mutex); ++ *should_up_board_mutex = false; ++ ++ if (down_interruptible(&pBoard->fw_control.mutex)) { ++ hailo_info(pBoard, "hailo_fw_control down_interruptible fail tgid:%d (process was interrupted or killed)\n", current->tgid); ++ return -ERESTARTSYS; ++ } ++ ++ if (copy_from_user(command, (void __user*)arg, sizeof(*command))) { ++ hailo_err(pBoard, "hailo_fw_control, copy_from_user fail\n"); ++ err = -ENOMEM; ++ goto l_exit; ++ } ++ ++ reinit_completion(&pBoard->fw_control.completion); ++ ++ err = hailo_pcie_write_firmware_control(&pBoard->pcie_resources, command); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed writing fw control to pcie\n"); ++ goto l_exit; ++ } ++ ++ // Wait for response ++ completion_result = wait_for_completion_interruptible_timeout(&pBoard->fw_control.completion, msecs_to_jiffies(command->timeout_ms)); ++ if (completion_result <= 0) { ++ if (0 == completion_result) { ++ hailo_err(pBoard, "hailo_fw_control, timeout waiting for control (timeout_ms=%d)\n", command->timeout_ms); ++ err = -ETIMEDOUT; ++ } else { ++ hailo_info(pBoard, "hailo_fw_control, wait for completion failed with err=%ld (process was interrupted or killed)\n", completion_result); ++ err = -EINTR; ++ } ++ goto l_exit; ++ } ++ ++ err = hailo_pcie_read_firmware_control(&pBoard->pcie_resources, command); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed reading fw control from pcie\n"); ++ goto l_exit; ++ } ++ ++ if (copy_to_user((void __user*)arg, command, sizeof(*command))) { ++ hailo_err(pBoard, "hailo_fw_control, copy_to_user fail\n"); ++ err = -ENOMEM; ++ goto l_exit; ++ } ++ ++l_exit: ++ up(&pBoard->fw_control.mutex); ++ return err; ++} ++ ++static long hailo_query_device_properties(struct hailo_pcie_board *board, unsigned long arg) ++{ ++ struct hailo_device_properties props = { ++ .desc_max_page_size = board->desc_max_page_size, ++ .allocation_mode = board->allocation_mode, ++ .dma_type = HAILO_DMA_TYPE_PCIE, ++ .dma_engines_count = board->vdma.vdma_engines_count, ++ .is_fw_loaded = hailo_pcie_is_firmware_loaded(&board->pcie_resources), ++ }; ++ ++ hailo_info(board, "HAILO_QUERY_DEVICE_PROPERTIES: desc_max_page_size=%u\n", props.desc_max_page_size); ++ ++ if (copy_to_user((void __user*)arg, &props, sizeof(props))) { ++ hailo_err(board, "HAILO_QUERY_DEVICE_PROPERTIES, copy_to_user failed\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static long hailo_query_driver_info(struct hailo_pcie_board *board, unsigned long arg) ++{ ++ struct hailo_driver_info info = { ++ .major_version = HAILO_DRV_VER_MAJOR, ++ .minor_version = HAILO_DRV_VER_MINOR, ++ .revision_version = HAILO_DRV_VER_REVISION ++ }; ++ ++ hailo_info(board, "HAILO_QUERY_DRIVER_INFO: major=%u, minor=%u, revision=%u\n", ++ info.major_version, info.minor_version, info.revision_version); ++ ++ if (copy_to_user((void __user*)arg, &info, sizeof(info))) { ++ hailo_err(board, "HAILO_QUERY_DRIVER_INFO, copy_to_user failed\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static long hailo_general_ioctl(struct hailo_pcie_board *board, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case HAILO_MEMORY_TRANSFER: ++ return hailo_memory_transfer_ioctl(board, arg); ++ case HAILO_QUERY_DEVICE_PROPERTIES: ++ return hailo_query_device_properties(board, arg); ++ case HAILO_QUERY_DRIVER_INFO: ++ return hailo_query_driver_info(board, arg); ++ default: ++ hailo_err(board, "Invalid general ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++static long hailo_nnc_ioctl(struct hailo_pcie_board *board, unsigned int cmd, unsigned long arg, ++ struct file *filp, bool *should_up_board_mutex) ++{ ++ switch (cmd) { ++ case HAILO_FW_CONTROL: ++ return hailo_fw_control(board, arg, should_up_board_mutex); ++ case HAILO_READ_NOTIFICATION: ++ return hailo_read_notification_ioctl(board, arg, filp, should_up_board_mutex); ++ case HAILO_DISABLE_NOTIFICATION: ++ return hailo_disable_notification(board, filp); ++ case HAILO_READ_LOG: ++ return hailo_read_log_ioctl(board, arg); ++ default: ++ hailo_err(board, "Invalid nnc ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++long hailo_pcie_fops_unlockedioctl(struct file* filp, unsigned int cmd, unsigned long arg) ++{ ++ long err = 0; ++ struct hailo_pcie_board* board = (struct hailo_pcie_board*) filp->private_data; ++ struct hailo_file_context *context = NULL; ++ bool should_up_board_mutex = true; ++ ++ ++ if (!board || !board->pDev) return -ENODEV; ++ ++ hailo_dbg(board, "(%d): fops_unlockedioctl. cmd:%d\n", current->tgid, _IOC_NR(cmd)); ++ ++ if (_IOC_DIR(cmd) & _IOC_READ) ++ { ++ err = !compatible_access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); ++ } ++ else if (_IOC_DIR(cmd) & _IOC_WRITE) ++ { ++ err = !compatible_access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); ++ } ++ ++ if (err) { ++ hailo_err(board, "Invalid ioctl parameter access 0x%x", cmd); ++ return -EFAULT; ++ } ++ ++ if (down_interruptible(&board->mutex)) { ++ hailo_err(board, "unlockedioctl down_interruptible failed"); ++ return -ERESTARTSYS; ++ } ++ BUG_ON(board->mutex.count != 0); ++ ++ context = find_file_context(board, filp); ++ if (NULL == context) { ++ hailo_err(board, "Invalid driver state, file context does not exist\n"); ++ up(&board->mutex); ++ return -EINVAL; ++ } ++ ++ if (false == context->is_valid) { ++ hailo_err(board, "Invalid file context\n"); ++ up(&board->mutex); ++ return -EINVAL; ++ } ++ ++ switch (_IOC_TYPE(cmd)) { ++ case HAILO_GENERAL_IOCTL_MAGIC: ++ err = hailo_general_ioctl(board, cmd, arg); ++ break; ++ case HAILO_VDMA_IOCTL_MAGIC: ++ err = hailo_vdma_ioctl(&context->vdma_context, &board->vdma, cmd, arg, filp, &board->mutex, ++ &should_up_board_mutex); ++ break; ++ case HAILO_SOC_IOCTL_MAGIC: ++ if (HAILO_ACCELERATOR_TYPE_SOC != board->pcie_resources.accelerator_type) { ++ hailo_err(board, "Ioctl %d is not supported on this accelerator type\n", _IOC_TYPE(cmd)); ++ err = -EINVAL; ++ } else { ++ err = hailo_soc_ioctl(board, &context->vdma_context, &board->vdma, cmd, arg); ++ } ++ break; ++ case HAILO_NNC_IOCTL_MAGIC: ++ if (HAILO_ACCELERATOR_TYPE_NNC != board->pcie_resources.accelerator_type) { ++ hailo_err(board, "Ioctl %d is not supported on this accelerator type\n", _IOC_TYPE(cmd)); ++ err = -EINVAL; ++ } else { ++ err = hailo_nnc_ioctl(board, cmd, arg, filp, &should_up_board_mutex); ++ } ++ break; ++ default: ++ hailo_err(board, "Invalid ioctl type %d\n", _IOC_TYPE(cmd)); ++ err = -ENOTTY; ++ } ++ ++ if (should_up_board_mutex) { ++ up(&board->mutex); ++ } ++ ++ hailo_dbg(board, "(%d): fops_unlockedioct: SUCCESS\n", current->tgid); ++ return err; ++ ++} ++ ++int hailo_pcie_fops_mmap(struct file* filp, struct vm_area_struct *vma) ++{ ++ int err = 0; ++ ++ uintptr_t vdma_handle = vma->vm_pgoff << PAGE_SHIFT; ++ ++ struct hailo_pcie_board* board = (struct hailo_pcie_board*)filp->private_data; ++ struct hailo_file_context *context = NULL; ++ ++ BUILD_BUG_ON_MSG(sizeof(vma->vm_pgoff) < sizeof(vdma_handle), ++ "If this expression fails to compile it means the target HW is not compatible with our approach to use " ++ "the page offset paramter of 'mmap' to pass the driver the 'handle' of the desired descriptor"); ++ ++ vma->vm_pgoff = 0; // vm_pgoff contains vdma_handle page offset, the actual offset from the phys addr is 0 ++ ++ hailo_info(board, "%d fops_mmap\n", current->tgid); ++ ++ if (!board || !board->pDev) return -ENODEV; ++ ++ if (down_interruptible(&board->mutex)) { ++ hailo_err(board, "hailo_pcie_fops_mmap down_interruptible fail tgid:%d\n", current->tgid); ++ return -ERESTARTSYS; ++ } ++ ++ context = find_file_context(board, filp); ++ if (NULL == context) { ++ up(&board->mutex); ++ hailo_err(board, "Invalid driver state, file context does not exist\n"); ++ return -EINVAL; ++ } ++ ++ if (false == context->is_valid) { ++ up(&board->mutex); ++ hailo_err(board, "Invalid file context\n"); ++ return -EINVAL; ++ } ++ ++ err = hailo_vdma_mmap(&context->vdma_context, &board->vdma, vma, vdma_handle); ++ up(&board->mutex); ++ return err; ++} +diff --git a/drivers/media/pci/hailo/src/fops.h b/drivers/media/pci/hailo/src/fops.h +new file mode 100644 +index 000000000000..a9ca67f4e3e3 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/fops.h +@@ -0,0 +1,22 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_FOPS_H_ ++#define _HAILO_PCI_FOPS_H_ ++ ++int hailo_pcie_fops_open(struct inode* inode, struct file* filp); ++int hailo_pcie_fops_release(struct inode* inode, struct file* filp); ++long hailo_pcie_fops_unlockedioctl(struct file* filp, unsigned int cmd, unsigned long arg); ++int hailo_pcie_fops_mmap(struct file* filp, struct vm_area_struct *vma); ++int hailo_pcie_driver_down(struct hailo_pcie_board *board); ++void hailo_pcie_ep_init(struct hailo_pcie_board *board); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) ++irqreturn_t hailo_irqhandler(int irq, void* dev_id, struct pt_regs *regs); ++#else ++irqreturn_t hailo_irqhandler(int irq, void* dev_id); ++#endif ++ ++#endif /* _HAILO_PCI_FOPS_H_ */ +diff --git a/drivers/media/pci/hailo/src/pci_soc_ioctl.c b/drivers/media/pci/hailo/src/pci_soc_ioctl.c +new file mode 100755 +index 000000000000..74db9b4403f6 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pci_soc_ioctl.c +@@ -0,0 +1,155 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2024 Hailo Technologies Ltd. All rights reserved. ++ **/ ++#include "pci_soc_ioctl.h" ++ ++#include "utils.h" ++#include "vdma_common.h" ++#include "utils/logs.h" ++#include "vdma/memory.h" ++ ++#define PCI_SOC_VDMA_ENGINE_INDEX (0) ++#define PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS (10000) ++ ++long hailo_soc_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case HAILO_SOC_CONNECT: ++ return hailo_soc_connect_ioctl(board, context, controller, arg); ++ case HAILO_SOC_CLOSE: ++ return hailo_soc_close_ioctl(board, controller, arg); ++ default: ++ hailo_err(board, "Invalid pcie EP ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++long hailo_soc_connect_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_soc_connect_params params; ++ struct hailo_vdma_channel *input_channel = NULL; ++ struct hailo_vdma_channel *output_channel = NULL; ++ struct hailo_vdma_engine *vdma_engine = NULL; ++ struct hailo_descriptors_list_buffer *input_descriptors_buffer = NULL; ++ struct hailo_descriptors_list_buffer *output_descriptors_buffer = NULL; ++ uint8_t depth = 0; ++ int err = 0; ++ long completion_result = 0; ++ ++ if (copy_from_user(¶ms, (void *)arg, sizeof(params))) { ++ hailo_err(board, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ // TODO: have pci_ep choose the channel indexes the soc will use - for now use 0 and 16 ++ params.input_channel_index = 0; ++ params.output_channel_index = 16; ++ ++ reinit_completion(&board->soc_connect_accepted); ++ hailo_soc_write_soc_connect(&board->pcie_resources); ++ ++ // Wait for completion ++ completion_result = wait_for_completion_interruptible_timeout(&board->soc_connect_accepted, ++ msecs_to_jiffies(PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS)); ++ if (0 > completion_result) { ++ if (0 == completion_result) { ++ hailo_err(board, "Timeout waiting for connect to be accepted (timeout_ms=%d)\n", PCI_SOC_WAIT_FOR_CONNECT_TIMEOUT_MS); ++ return -ETIMEDOUT; ++ } else { ++ hailo_info(board, "soc connect failed with err=%ld (process was interrupted or killed)\n", ++ completion_result); ++ return -EINTR; ++ } ++ } ++ ++ vdma_engine = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ input_channel = &vdma_engine->channels[params.input_channel_index]; ++ output_channel = &vdma_engine->channels[params.output_channel_index]; ++ ++ input_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.input_desc_handle); ++ output_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.output_desc_handle); ++ if (NULL == input_descriptors_buffer || NULL == output_descriptors_buffer) { ++ hailo_dev_err(&board->pDev->dev, "input / output descriptors buffer not found \n"); ++ return -EINVAL; ++ } ++ ++ // Make sure channels that we are accepting are not already enabled ++ if (0 != (vdma_engine->enabled_channels & params.input_channel_index) || ++ 0 != (vdma_engine->enabled_channels & params.output_channel_index)) { ++ hailo_dev_err(&board->pDev->dev, "Trying to accept already enabled channels\n"); ++ return -EINVAL; ++ } ++ ++ if (!is_powerof2((size_t)input_descriptors_buffer->desc_list.desc_count) || ++ !is_powerof2((size_t)output_descriptors_buffer->desc_list.desc_count)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid desc list size\n"); ++ return -EINVAL; ++ } ++ ++ // configure and start input channel ++ depth = ceil_log2(input_descriptors_buffer->desc_list.desc_count); ++ // DMA Direction is only to get channel index - so ++ err = hailo_vdma_start_channel(input_channel->host_regs, input_descriptors_buffer->dma_address, depth, ++ board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_dev_err(&board->pDev->dev, "Error starting vdma input channel index %u\n", params.input_channel_index); ++ return -EINVAL; ++ } ++ ++ // configure and start output channel ++ depth = ceil_log2(output_descriptors_buffer->desc_list.desc_count); ++ // DMA Direction is only to get channel index - so ++ err = hailo_vdma_start_channel(output_channel->host_regs, output_descriptors_buffer->dma_address, depth, ++ board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_dev_err(&board->pDev->dev, "Error starting vdma output channel index %u\n", params.output_channel_index); ++ // Close input channel ++ hailo_vdma_stop_channel(input_channel->host_regs); ++ return -EINVAL; ++ } ++ ++ if (copy_to_user((void *)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(&board->pDev->dev, "copy_to_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++long hailo_soc_close_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_soc_close_params params; ++ struct hailo_vdma_channel *input_channel = NULL; ++ struct hailo_vdma_channel *output_channel = NULL; ++ struct hailo_vdma_engine *vdma_engine = NULL; ++ ++ if (copy_from_user(¶ms, (void *)arg, sizeof(params))) { ++ hailo_dev_err(&board->pDev->dev, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ vdma_engine = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ ++ if (!hailo_check_channel_index(params.input_channel_index, controller->hw->src_channels_bitmask, true)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid input channel index %u\n", params.input_channel_index); ++ return -EINVAL; ++ } ++ ++ if (!hailo_check_channel_index(params.output_channel_index, controller->hw->src_channels_bitmask, false)) { ++ hailo_dev_err(&board->pDev->dev, "Invalid output channel index %u\n", params.output_channel_index); ++ return -EINVAL; ++ } ++ ++ input_channel = &vdma_engine->channels[params.input_channel_index]; ++ output_channel = &vdma_engine->channels[params.output_channel_index]; ++ ++ // Close channels ++ hailo_vdma_stop_channel(input_channel->host_regs); ++ hailo_vdma_stop_channel(output_channel->host_regs); ++ ++ hailo_pcie_write_firmware_driver_shutdown(&board->pcie_resources); ++ return 0; ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/src/pci_soc_ioctl.h b/drivers/media/pci/hailo/src/pci_soc_ioctl.h +new file mode 100755 +index 000000000000..474fda9fd332 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pci_soc_ioctl.h +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2024 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_SOC_IOCTL_H_ ++#define _HAILO_PCI_SOC_IOCTL_H_ ++ ++#include "vdma/ioctl.h" ++#include "pcie.h" ++ ++ ++long hailo_soc_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned int cmd, unsigned long arg); ++long hailo_soc_connect_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_soc_close_ioctl(struct hailo_pcie_board *board, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++#endif // _HAILO_PCI_SOC_IOCTL_H_ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/src/pcie.c b/drivers/media/pci/hailo/src/pcie.c +new file mode 100644 +index 000000000000..170ae819bb0f +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pcie.c +@@ -0,0 +1,1095 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) ++#include ++#endif ++ ++#define KERNEL_CODE 1 ++ ++#include "hailo_ioctl_common.h" ++#include "pcie.h" ++#include "fops.h" ++#include "sysfs.h" ++#include "utils/logs.h" ++#include "utils/compact.h" ++#include "vdma/vdma.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION( 5, 4, 0 ) ++#include ++#endif ++ ++// enum that represents values for the driver parameter to either force buffer from driver , userspace or not force ++// and let driver decide ++enum hailo_allocate_driver_buffer_driver_param { ++ HAILO_NO_FORCE_BUFFER = 0, ++ HAILO_FORCE_BUFFER_FROM_USERSPACE = 1, ++ HAILO_FORCE_BUFFER_FROM_DRIVER = 2, ++}; ++ ++//Debug flag ++static int force_desc_page_size = 0; ++static bool g_is_power_mode_enabled = true; ++static int force_allocation_from_driver = HAILO_NO_FORCE_BUFFER; ++static bool force_hailo15_legacy_mode = false; ++ ++#define DEVICE_NODE_NAME "hailo" ++static int char_major = 0; ++static struct class *chardev_class; ++ ++static LIST_HEAD(g_hailo_board_list); ++static struct semaphore g_hailo_add_board_mutex = __SEMAPHORE_INITIALIZER(g_hailo_add_board_mutex, 1); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) ++#define HAILO_IRQ_FLAGS (SA_SHIRQ | SA_INTERRUPT) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) ++#define HAILO_IRQ_FLAGS (IRQF_SHARED | IRQF_DISABLED) ++#else ++#define HAILO_IRQ_FLAGS (IRQF_SHARED) ++#endif ++ ++ /* **************************** ++ ******************************* */ ++bool power_mode_enabled(void) ++{ ++#if !defined(HAILO_EMULATOR) ++ return g_is_power_mode_enabled; ++#else /* !defined(HAILO_EMULATOR) */ ++ return false; ++#endif /* !defined(HAILO_EMULATOR) */ ++} ++ ++ ++/** ++ * Due to an HW bug, on system with low MaxReadReq ( < 512) we need to use different descriptors size. ++ * Returns the max descriptor size or 0 on failure. ++ */ ++static int hailo_get_desc_page_size(struct pci_dev *pdev, u32 *out_page_size) ++{ ++ u16 pcie_device_control = 0; ++ int err = 0; ++ // The default page size must be smaller/equal to 32K (due to PLDA registers limit). ++ const u32 max_page_size = 32u * 1024u; ++ const u32 defualt_page_size = min((u32)PAGE_SIZE, max_page_size); ++ ++ if (force_desc_page_size != 0) { ++ // The user given desc_page_size as a module parameter ++ if ((force_desc_page_size & (force_desc_page_size - 1)) != 0) { ++ pci_err(pdev, "force_desc_page_size must be a power of 2\n"); ++ return -EINVAL; ++ } ++ ++ if (force_desc_page_size > max_page_size) { ++ pci_err(pdev, "force_desc_page_size %d mustn't be larger than %u", force_desc_page_size, max_page_size); ++ return -EINVAL; ++ } ++ ++ pci_notice(pdev, "Probing: Force setting max_desc_page_size to %d (recommended value is %lu)\n", ++ force_desc_page_size, PAGE_SIZE); ++ *out_page_size = force_desc_page_size; ++ return 0; ++ } ++ ++ err = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &pcie_device_control); ++ if (err < 0) { ++ pci_err(pdev, "Couldn't read DEVCTL capability\n"); ++ return err; ++ } ++ ++ switch (pcie_device_control & PCI_EXP_DEVCTL_READRQ) { ++ case PCI_EXP_DEVCTL_READRQ_128B: ++ pci_notice(pdev, "Probing: Setting max_desc_page_size to 128 (recommended value is %u)\n", defualt_page_size); ++ *out_page_size = 128; ++ return 0; ++ case PCI_EXP_DEVCTL_READRQ_256B: ++ pci_notice(pdev, "Probing: Setting max_desc_page_size to 256 (recommended value is %u)\n", defualt_page_size); ++ *out_page_size = 256; ++ return 0; ++ default: ++ pci_notice(pdev, "Probing: Setting max_desc_page_size to %u, (page_size=%lu)\n", defualt_page_size, PAGE_SIZE); ++ *out_page_size = defualt_page_size; ++ return 0; ++ }; ++} ++ ++// should be called only from fops_open (once) ++struct hailo_pcie_board* hailo_pcie_get_board_index(u32 index) ++{ ++ struct hailo_pcie_board *pBoard, *pRet = NULL; ++ ++ down(&g_hailo_add_board_mutex); ++ list_for_each_entry(pBoard, &g_hailo_board_list, board_list) ++ { ++ if ( index == pBoard->board_index ) ++ { ++ atomic_inc(&pBoard->ref_count); ++ pRet = pBoard; ++ break; ++ } ++ } ++ up(&g_hailo_add_board_mutex); ++ ++ return pRet; ++} ++ ++/** ++ * hailo_pcie_disable_aspm - Disable ASPM states ++ * @board: pointer to PCI board struct ++ * @state: bit-mask of ASPM states to disable ++ * @locked: indication if this context holds pci_bus_sem locked. ++ * ++ * Some devices *must* have certain ASPM states disabled per hardware errata. ++ **/ ++static int hailo_pcie_disable_aspm(struct hailo_pcie_board *board, u16 state, bool locked) ++{ ++ struct pci_dev *pdev = board->pDev; ++ struct pci_dev *parent = pdev->bus->self; ++ u16 aspm_dis_mask = 0; ++ u16 pdev_aspmc = 0; ++ u16 parent_aspmc = 0; ++ int err = 0; ++ ++ switch (state) { ++ case PCIE_LINK_STATE_L0S: ++ aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L0S; ++ break; ++ case PCIE_LINK_STATE_L1: ++ aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L1; ++ break; ++ default: ++ break; ++ } ++ ++ err = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc); ++ if (err < 0) { ++ hailo_err(board, "Couldn't read LNKCTL capability\n"); ++ return err; ++ } ++ ++ pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC; ++ ++ if (parent) { ++ err = pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_aspmc); ++ if (err < 0) { ++ hailo_err(board, "Couldn't read slot LNKCTL capability\n"); ++ return err; ++ } ++ parent_aspmc &= PCI_EXP_LNKCTL_ASPMC; ++ } ++ ++ hailo_notice(board, "Disabling ASPM %s %s\n", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); ++ ++ // Disable L0s even if it is currently disabled as ASPM states can be enabled by the kernel when changing power modes ++#ifdef CONFIG_PCIEASPM ++ if (locked) { ++ // Older kernel versions (<5.2.21) don't return value for this functions, so we try manual disabling anyway ++ (void)pci_disable_link_state_locked(pdev, state); ++ } else { ++ (void)pci_disable_link_state(pdev, state); ++ } ++ ++ /* Double-check ASPM control. If not disabled by the above, the ++ * BIOS is preventing that from happening (or CONFIG_PCIEASPM is ++ * not enabled); override by writing PCI config space directly. ++ */ ++ err = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc); ++ if (err < 0) { ++ hailo_err(board, "Couldn't read LNKCTL capability\n"); ++ return err; ++ } ++ pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC; ++ ++ if (!(aspm_dis_mask & pdev_aspmc)) { ++ hailo_notice(board, "Successfully disabled ASPM %s %s\n", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); ++ return 0; ++ } ++#endif ++ ++ /* Both device and parent should have the same ASPM setting. ++ * Disable ASPM in downstream component first and then upstream. ++ */ ++ err = pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_dis_mask); ++ if (err < 0) { ++ hailo_err(board, "Couldn't read LNKCTL capability\n"); ++ return err; ++ } ++ if (parent) { ++ err = pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, aspm_dis_mask); ++ if (err < 0) { ++ hailo_err(board, "Couldn't read slot LNKCTL capability\n"); ++ return err; ++ } ++ } ++ hailo_notice(board, "Manually disabled ASPM %s %s\n", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", ++ (aspm_dis_mask & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); ++ ++ return 0; ++} ++ ++static void hailo_pcie_insert_board(struct hailo_pcie_board* pBoard) ++{ ++ u32 index = 0; ++ struct hailo_pcie_board *pCurrent, *pNext; ++ ++ ++ down(&g_hailo_add_board_mutex); ++ if ( list_empty(&g_hailo_board_list) || ++ list_first_entry(&g_hailo_board_list, struct hailo_pcie_board, board_list)->board_index > 0) ++ { ++ pBoard->board_index = 0; ++ list_add(&pBoard->board_list, &g_hailo_board_list); ++ ++ up(&g_hailo_add_board_mutex); ++ return; ++ } ++ ++ list_for_each_entry_safe(pCurrent, pNext, &g_hailo_board_list, board_list) ++ { ++ index = pCurrent->board_index+1; ++ if( list_is_last(&pCurrent->board_list, &g_hailo_board_list) || (index != pNext->board_index)) ++ { ++ break; ++ } ++ } ++ ++ pBoard->board_index = index; ++ list_add(&pBoard->board_list, &pCurrent->board_list); ++ ++ up(&g_hailo_add_board_mutex); ++ ++ return; ++} ++ ++static void hailo_pcie_remove_board(struct hailo_pcie_board* pBoard) ++{ ++ down(&g_hailo_add_board_mutex); ++ if (pBoard) ++ { ++ list_del(&pBoard->board_list); ++ } ++ up(&g_hailo_add_board_mutex); ++} ++ ++static int hailo_write_config(struct hailo_pcie_resources *resources, struct device *dev, ++ const struct hailo_config_constants *config_consts) ++{ ++ const struct firmware *config = NULL; ++ int err = 0; ++ ++ if (NULL == config_consts->filename) { ++ // Config not supported for platform ++ return 0; ++ } ++ ++ err = request_firmware_direct(&config, config_consts->filename, dev); ++ if (err < 0) { ++ hailo_dev_info(dev, "Config %s not found\n", config_consts->filename); ++ return 0; ++ } ++ ++ hailo_dev_notice(dev, "Writing config %s\n", config_consts->filename); ++ ++ err = hailo_pcie_write_config_common(resources, config->data, config->size, config_consts); ++ if (err < 0) { ++ if (-EINVAL == err) { ++ hailo_dev_warn(dev, "Config size %zu is bigger than max %zu\n", config->size, config_consts->max_size); ++ } ++ release_firmware(config); ++ return err; ++ } ++ ++ release_firmware(config); ++ return 0; ++} ++ ++static bool wait_for_firmware_completion(struct completion *fw_load_completion) ++{ ++ return (0 != wait_for_completion_timeout(fw_load_completion, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS))); ++} ++ ++static int hailo_load_firmware(struct hailo_pcie_resources *resources, ++ struct device *dev, struct completion *fw_load_completion) ++{ ++ const struct firmware *firmware = NULL; ++ int err = 0; ++ u32 boot_status = 0; ++ ++ if (hailo_pcie_is_firmware_loaded(resources)) { ++ hailo_dev_warn(dev, "Firmware was already loaded\n"); ++ return 0; ++ } ++ ++ reinit_completion(fw_load_completion); ++ ++ err = hailo_write_config(resources, dev, hailo_pcie_get_board_config_constants(resources->board_type)); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing board config"); ++ return err; ++ } ++ ++ err = hailo_write_config(resources, dev, hailo_pcie_get_user_config_constants(resources->board_type)); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing fw config"); ++ return err; ++ } ++ ++ // read firmware file ++ err = request_firmware_direct(&firmware, hailo_pcie_get_fw_filename(resources->board_type), dev); ++ if (err < 0) { ++ hailo_dev_warn(dev, "Firmware file not found (/lib/firmware/%s), please upload the firmware manually \n", ++ hailo_pcie_get_fw_filename(resources->board_type)); ++ return 0; ++ } ++ ++ err = hailo_pcie_write_firmware(resources, firmware->data, firmware->size); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing firmware. err %d\n", err); ++ release_firmware(firmware); ++ return err; ++ } ++ ++ release_firmware(firmware); ++ ++ if (!wait_for_firmware_completion(fw_load_completion)) { ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ return -ETIMEDOUT; ++ } ++ ++ hailo_dev_notice(dev, "Firmware was loaded successfully\n"); ++ return 0; ++} ++ ++static int hailo_load_firmware_batch(struct hailo_pcie_resources *resources, ++ struct device *dev, struct completion *fw_load_completion) ++{ ++ u32 boot_status = 0; ++ u32 pcie_finished = 1; ++ int err = 0; ++ ++ if (hailo_pcie_is_firmware_loaded(resources)) { ++ hailo_dev_warn(dev, "Firmware batch was already loaded\n"); ++ return 0; ++ } ++ ++ init_completion(fw_load_completion); ++ ++ err = hailo_pcie_write_firmware_batch(dev, resources, FIRST_STAGE); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ return err; ++ } ++ ++ hailo_trigger_firmware_boot(resources); ++ ++ if (!wait_for_firmware_completion(fw_load_completion)) { ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ return -ETIMEDOUT; ++ } ++ reinit_completion(fw_load_completion); ++ ++ err = hailo_pcie_write_firmware_batch(dev, resources, SECOND_STAGE); ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ return err; ++ } ++ ++ // TODO: HRT-13838 - Remove, move address to compat, make write_memory static ++ write_memory(resources, 0x84000000, (void*)&pcie_finished, sizeof(pcie_finished)); ++ ++ if (!wait_for_firmware_completion(fw_load_completion)) { ++ boot_status = hailo_get_boot_status(resources); ++ hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ return -ETIMEDOUT; ++ } ++ ++ hailo_dev_notice(dev, "Firmware Batch loaded successfully\n"); ++ ++ return 0; ++} ++ ++static int hailo_activate_board(struct hailo_pcie_board *board) ++{ ++ int err = 0; ++ ++ (void)hailo_pcie_disable_aspm(board, PCIE_LINK_STATE_L0S, false); ++ ++ err = hailo_enable_interrupts(board); ++ if (err < 0) { ++ hailo_err(board, "Failed Enabling interrupts %d\n", err); ++ return err; ++ } ++ ++ switch (board->pcie_resources.board_type) { ++ case HAILO_BOARD_TYPE_HAILO10H: ++ err = hailo_load_firmware_batch(&board->pcie_resources, &board->pDev->dev, ++ &board->fw_loaded_completion); ++ break; ++ case HAILO_BOARD_TYPE_HAILO10H_LEGACY: ++ case HAILO_BOARD_TYPE_PLUTO: ++ case HAILO_BOARD_TYPE_HAILO8: ++ err = hailo_load_firmware(&board->pcie_resources, &board->pDev->dev, ++ &board->fw_loaded_completion); ++ break; ++ default: ++ hailo_err(board, "Invalid board type"); ++ err = -EINVAL; ++ } ++ if (err < 0) { ++ hailo_err(board, "Firmware load failed\n"); ++ hailo_disable_interrupts(board); ++ return err; ++ } ++ ++ hailo_disable_interrupts(board); ++ ++ if (power_mode_enabled()) { ++ // Setting the device to low power state, until the user opens the device ++ err = pci_set_power_state(board->pDev, PCI_D3hot); ++ if (err < 0) { ++ hailo_err(board, "Set power state failed %d\n", err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++int hailo_enable_interrupts(struct hailo_pcie_board *board) ++{ ++ int err = 0; ++ ++ if (board->interrupts_enabled) { ++ hailo_crit(board, "Failed enabling interrupts (already enabled)\n"); ++ return -EINVAL; ++ } ++ ++ // TODO HRT-2253: use new api for enabling msi: (pci_alloc_irq_vectors) ++ if ((err = pci_enable_msi(board->pDev))) { ++ hailo_err(board, "Failed to enable MSI %d\n", err); ++ return err; ++ } ++ hailo_info(board, "Enabled MSI interrupt\n"); ++ ++ err = request_irq(board->pDev->irq, hailo_irqhandler, HAILO_IRQ_FLAGS, DRIVER_NAME, board); ++ if (err) { ++ hailo_err(board, "request_irq failed %d\n", err); ++ pci_disable_msi(board->pDev); ++ return err; ++ } ++ hailo_info(board, "irq enabled %u\n", board->pDev->irq); ++ ++ hailo_pcie_enable_interrupts(&board->pcie_resources); ++ ++ board->interrupts_enabled = true; ++ return 0; ++} ++ ++void hailo_disable_interrupts(struct hailo_pcie_board *board) ++{ ++ // Sanity Check ++ if ((NULL == board) || (NULL == board->pDev)) { ++ pr_err("Failed to access board or device\n"); ++ return; ++ } ++ ++ if (!board->interrupts_enabled) { ++ return; ++ } ++ ++ board->interrupts_enabled = false; ++ hailo_pcie_disable_interrupts(&board->pcie_resources); ++ free_irq(board->pDev->irq, board); ++ pci_disable_msi(board->pDev); ++} ++ ++static int hailo_bar_iomap(struct pci_dev *pdev, int bar, struct hailo_resource *resource) ++{ ++ resource->size = pci_resource_len(pdev, bar); ++ resource->address = (uintptr_t)(pci_iomap(pdev, bar, resource->size)); ++ ++ if (!resource->size || !resource->address) { ++ pci_err(pdev, "Probing: Invalid PCIe BAR %d", bar); ++ return -EINVAL; ++ } ++ ++ pci_notice(pdev, "Probing: mapped bar %d - %p %zu\n", bar, ++ (void*)resource->address, resource->size); ++ return 0; ++} ++ ++static void hailo_bar_iounmap(struct pci_dev *pdev, struct hailo_resource *resource) ++{ ++ if (resource->address) { ++ pci_iounmap(pdev, (void*)resource->address); ++ resource->address = 0; ++ resource->size = 0; ++ } ++} ++ ++static int pcie_resources_init(struct pci_dev *pdev, struct hailo_pcie_resources *resources, ++ enum hailo_board_type board_type) ++{ ++ int err = -EINVAL; ++ if (board_type >= HAILO_BOARD_TYPE_COUNT) { ++ pci_err(pdev, "Probing: Invalid board type %d\n", (int)board_type); ++ err = -EINVAL; ++ goto failure_exit; ++ } ++ ++ err = pci_request_regions(pdev, DRIVER_NAME); ++ if (err < 0) { ++ pci_err(pdev, "Probing: Error allocating bars %d\n", err); ++ goto failure_exit; ++ } ++ ++ err = hailo_bar_iomap(pdev, HAILO_PCIE_CONFIG_BAR, &resources->config); ++ if (err < 0) { ++ goto failure_release_regions; ++ } ++ ++ err = hailo_bar_iomap(pdev, HAILO_PCIE_VDMA_REGS_BAR, &resources->vdma_registers); ++ if (err < 0) { ++ goto failure_release_config; ++ } ++ ++ err = hailo_bar_iomap(pdev, HAILO_PCIE_FW_ACCESS_BAR, &resources->fw_access); ++ if (err < 0) { ++ goto failure_release_vdma_regs; ++ } ++ ++ ++ // There is no HAILO15 as mercury through pcie unless it's legacy mode (H15 as accelerator) or HAILO-10H ++ if (HAILO_BOARD_TYPE_HAILO15 == board_type){ ++ if (true == force_hailo15_legacy_mode) { ++ board_type = HAILO_BOARD_TYPE_HAILO10H_LEGACY; ++ } else { ++ board_type = HAILO_BOARD_TYPE_HAILO10H; ++ } ++ } ++ ++ resources->board_type = board_type; ++ ++ err = hailo_set_device_type(resources); ++ if (err < 0) { ++ goto failure_release_fw_access; ++ } ++ ++ if (!hailo_pcie_is_device_connected(resources)) { ++ pci_err(pdev, "Probing: Failed reading device BARs, device may be disconnected\n"); ++ err = -ENODEV; ++ goto failure_release_fw_access; ++ } ++ ++ return 0; ++ ++failure_release_fw_access: ++ hailo_bar_iounmap(pdev, &resources->fw_access); ++failure_release_vdma_regs: ++ hailo_bar_iounmap(pdev, &resources->vdma_registers); ++failure_release_config: ++ hailo_bar_iounmap(pdev, &resources->config); ++failure_release_regions: ++ pci_release_regions(pdev); ++failure_exit: ++ return err; ++} ++ ++static void pcie_resources_release(struct pci_dev *pdev, struct hailo_pcie_resources *resources) ++{ ++ hailo_bar_iounmap(pdev, &resources->config); ++ hailo_bar_iounmap(pdev, &resources->vdma_registers); ++ hailo_bar_iounmap(pdev, &resources->fw_access); ++ pci_release_regions(pdev); ++} ++ ++static void update_channel_interrupts(struct hailo_vdma_controller *controller, ++ size_t engine_index, u32 channels_bitmap) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board*) dev_get_drvdata(controller->dev); ++ if (engine_index >= board->vdma.vdma_engines_count) { ++ hailo_err(board, "Invalid engine index %zu", engine_index); ++ return; ++ } ++ ++ hailo_pcie_update_channel_interrupts_mask(&board->pcie_resources, channels_bitmap); ++} ++ ++static struct hailo_vdma_controller_ops pcie_vdma_controller_ops = { ++ .update_channel_interrupts = update_channel_interrupts, ++}; ++ ++ ++static int hailo_pcie_vdma_controller_init(struct hailo_vdma_controller *controller, ++ struct device *dev, struct hailo_resource *vdma_registers) ++{ ++ const size_t engines_count = 1; ++ return hailo_vdma_controller_init(controller, dev, &hailo_pcie_vdma_hw, ++ &pcie_vdma_controller_ops, vdma_registers, engines_count); ++} ++ ++// Tries to check if address allocated with kmalloc is dma capable. ++// If kmalloc address is not dma capable we assume other addresses ++// won't be dma capable as well. ++static bool is_kmalloc_dma_capable(struct device *dev) ++{ ++ void *check_addr = NULL; ++ dma_addr_t dma_addr = 0; ++ phys_addr_t phys_addr = 0; ++ bool capable = false; ++ ++ if (!dev->dma_mask) { ++ return false; ++ } ++ ++ check_addr = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (NULL == check_addr) { ++ dev_err(dev, "failed allocating page!\n"); ++ return false; ++ } ++ ++ phys_addr = virt_to_phys(check_addr); ++ dma_addr = phys_to_dma(dev, phys_addr); ++ ++ capable = is_dma_capable(dev, dma_addr, PAGE_SIZE); ++ kfree(check_addr); ++ return capable; ++} ++ ++static int hailo_get_allocation_mode(struct pci_dev *pdev, enum hailo_allocation_mode *allocation_mode) ++{ ++ // Check if module paramater was given to override driver choice ++ if (HAILO_NO_FORCE_BUFFER != force_allocation_from_driver) { ++ if (HAILO_FORCE_BUFFER_FROM_USERSPACE == force_allocation_from_driver) { ++ *allocation_mode = HAILO_ALLOCATION_MODE_USERSPACE; ++ pci_notice(pdev, "Probing: Using userspace allocated vdma buffers\n"); ++ } ++ else if (HAILO_FORCE_BUFFER_FROM_DRIVER == force_allocation_from_driver) { ++ *allocation_mode = HAILO_ALLOCATION_MODE_DRIVER; ++ pci_notice(pdev, "Probing: Using driver allocated vdma buffers\n"); ++ } ++ else { ++ pci_err(pdev, "Invalid value for force allocation driver paramater - value given: %d!\n", ++ force_allocation_from_driver); ++ return -EINVAL; ++ } ++ ++ return 0; ++ } ++ ++ if (is_kmalloc_dma_capable(&pdev->dev)) { ++ *allocation_mode = HAILO_ALLOCATION_MODE_USERSPACE; ++ pci_notice(pdev, "Probing: Using userspace allocated vdma buffers\n"); ++ } else { ++ *allocation_mode = HAILO_ALLOCATION_MODE_DRIVER; ++ pci_notice(pdev, "Probing: Using driver allocated vdma buffers\n"); ++ } ++ ++ return 0; ++} ++ ++static int hailo_pcie_probe(struct pci_dev* pDev, const struct pci_device_id* id) ++{ ++ struct hailo_pcie_board * pBoard; ++ struct device *char_device = NULL; ++ int err = -EINVAL; ++ ++ pci_notice(pDev, "Probing on: %04x:%04x...\n", pDev->vendor, pDev->device); ++#ifdef HAILO_EMULATOR ++ pci_notice(pDev, "PCIe driver was compiled in emulator mode\n"); ++#endif /* HAILO_EMULATOR */ ++ if (!g_is_power_mode_enabled) { ++ pci_notice(pDev, "PCIe driver was compiled with power modes disabled\n"); ++ } ++ ++ /* Initialize device extension for the board*/ ++ pci_notice(pDev, "Probing: Allocate memory for device extension, %zu\n", sizeof(struct hailo_pcie_board)); ++ pBoard = (struct hailo_pcie_board*) kzalloc( sizeof(struct hailo_pcie_board), GFP_KERNEL); ++ if (pBoard == NULL) ++ { ++ pci_err(pDev, "Probing: Failed to allocate memory for device extension structure\n"); ++ err = -ENOMEM; ++ goto probe_exit; ++ } ++ ++ pBoard->pDev = pDev; ++ ++ if ( (err = pci_enable_device(pDev)) ) ++ { ++ pci_err(pDev, "Probing: Failed calling pci_enable_device %d\n", err); ++ goto probe_free_board; ++ } ++ pci_notice(pDev, "Probing: Device enabled\n"); ++ ++ pci_set_master(pDev); ++ ++ err = pcie_resources_init(pDev, &pBoard->pcie_resources, id->driver_data); ++ if (err < 0) { ++ pci_err(pDev, "Probing: Failed init pcie resources"); ++ goto probe_disable_device; ++ } ++ ++ err = hailo_get_desc_page_size(pDev, &pBoard->desc_max_page_size); ++ if (err < 0) { ++ goto probe_release_pcie_resources; ++ } ++ ++ pBoard->interrupts_enabled = false; ++ init_completion(&pBoard->fw_loaded_completion); ++ init_completion(&pBoard->soc_connect_accepted); ++ ++ sema_init(&pBoard->mutex, 1); ++ atomic_set(&pBoard->ref_count, 0); ++ INIT_LIST_HEAD(&pBoard->open_files_list); ++ ++ sema_init(&pBoard->fw_control.mutex, 1); ++ spin_lock_init(&pBoard->notification_read_spinlock); ++ init_completion(&pBoard->fw_control.completion); ++ ++ init_completion(&pBoard->driver_down.reset_completed); ++ ++ INIT_LIST_HEAD(&pBoard->notification_wait_list); ++ ++ memset(&pBoard->notification_cache, 0, sizeof(pBoard->notification_cache)); ++ memset(&pBoard->memory_transfer_params, 0, sizeof(pBoard->memory_transfer_params)); ++ ++ err = hailo_pcie_vdma_controller_init(&pBoard->vdma, &pBoard->pDev->dev, ++ &pBoard->pcie_resources.vdma_registers); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed init vdma controller %d\n", err); ++ goto probe_release_pcie_resources; ++ } ++ ++ // Checks the dma mask => it must be called after the device's dma_mask is set by hailo_pcie_vdma_controller_init ++ err = hailo_get_allocation_mode(pDev, &pBoard->allocation_mode); ++ if (err < 0) { ++ pci_err(pDev, "Failed determining allocation of buffers from driver. error type: %d\n", err); ++ goto probe_release_pcie_resources; ++ } ++ ++ err = hailo_activate_board(pBoard); ++ if (err < 0) { ++ hailo_err(pBoard, "Failed activating board %d\n", err); ++ goto probe_release_pcie_resources; ++ } ++ ++ /* Keep track on the device, in order, to be able to remove it later */ ++ pci_set_drvdata(pDev, pBoard); ++ hailo_pcie_insert_board(pBoard); ++ ++ /* Create dynamically the device node*/ ++ char_device = device_create_with_groups(chardev_class, NULL, ++ MKDEV(char_major, pBoard->board_index), ++ pBoard, ++ g_hailo_dev_groups, ++ DEVICE_NODE_NAME"%d", pBoard->board_index); ++ if (IS_ERR(char_device)) { ++ hailo_err(pBoard, "Failed creating dynamic device %d\n", pBoard->board_index); ++ err = PTR_ERR(char_device); ++ goto probe_remove_board; ++ } ++ ++ hailo_notice(pBoard, "Probing: Added board %0x-%0x, /dev/hailo%d\n", pDev->vendor, pDev->device, pBoard->board_index); ++ ++ return 0; ++ ++probe_remove_board: ++ hailo_pcie_remove_board(pBoard); ++ ++probe_release_pcie_resources: ++ pcie_resources_release(pBoard->pDev, &pBoard->pcie_resources); ++ ++probe_disable_device: ++ pci_disable_device(pDev); ++ ++probe_free_board: ++ kfree(pBoard); ++ ++probe_exit: ++ ++ return err; ++} ++ ++static void hailo_pcie_remove(struct pci_dev* pDev) ++{ ++ struct hailo_pcie_board* pBoard = (struct hailo_pcie_board*) pci_get_drvdata(pDev); ++ struct hailo_notification_wait *cursor = NULL; ++ ++ pci_notice(pDev, "Remove: Releasing board\n"); ++ ++ if (pBoard) ++ { ++ ++ // lock board to wait for any pending operations and for synchronization with open ++ down(&pBoard->mutex); ++ ++ ++ // remove board from active boards list ++ hailo_pcie_remove_board(pBoard); ++ ++ ++ /* Delete the device node */ ++ device_destroy(chardev_class, MKDEV(char_major, pBoard->board_index)); ++ ++ // disable interrupts - will only disable if they have not been disabled in release already ++ hailo_disable_interrupts(pBoard); ++ ++ pcie_resources_release(pBoard->pDev, &pBoard->pcie_resources); ++ ++ // deassociate device from board to be picked up by char device ++ pBoard->pDev = NULL; ++ ++ pBoard->vdma.dev = NULL; ++ ++ pci_disable_device(pDev); ++ ++ pci_set_drvdata(pDev, NULL); ++ ++ // Lock rcu_read_lock and send notification_completion to wake anyone waiting on the notification_wait_list when removed ++ rcu_read_lock(); ++ list_for_each_entry_rcu(cursor, &pBoard->notification_wait_list, notification_wait_list) { ++ cursor->is_disabled = true; ++ complete(&cursor->notification_completion); ++ } ++ rcu_read_unlock(); ++ ++ up(&pBoard->mutex); ++ ++ if ( 0 == atomic_read(&pBoard->ref_count) ) ++ { ++ // nobody has the board open - free ++ pci_notice(pDev, "Remove: Freed board, /dev/hailo%d\n", pBoard->board_index); ++ kfree(pBoard); ++ } ++ else ++ { ++ // board resources are freed on last close ++ pci_notice(pDev, "Remove: Scheduled for board removal, /dev/hailo%d\n", pBoard->board_index); ++ } ++ } ++ ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int hailo_pcie_suspend(struct device *dev) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board*) dev_get_drvdata(dev); ++ struct hailo_file_context *cur = NULL; ++ int err = 0; ++ ++ // lock board to wait for any pending operations ++ down(&board->mutex); ++ ++ // Disable all interrupts. All interrupts from Hailo chip would be masked. ++ hailo_disable_interrupts(board); ++ ++ // Close all vDMA channels ++ if (board->vdma.used_by_filp != NULL) { ++ err = hailo_pcie_driver_down(board); ++ if (err < 0) { ++ dev_notice(dev, "Error while trying to call FW to close vdma channels\n"); ++ } ++ } ++ ++ // Un validate all activae file contexts so every new action would return error to the user. ++ list_for_each_entry(cur, &board->open_files_list, open_files_list) { ++ cur->is_valid = false; ++ } ++ ++ // Release board ++ up(&board->mutex); ++ ++ dev_notice(dev, "PM's suspend\n"); ++ // Continue system suspend ++ return err; ++} ++ ++static int hailo_pcie_resume(struct device *dev) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board*) dev_get_drvdata(dev); ++ int err = 0; ++ ++ if ((err = hailo_activate_board(board)) < 0) { ++ dev_err(dev, "Failed activating board %d\n", err); ++ return err; ++ } ++ ++ dev_notice(dev, "PM's resume\n"); ++ return 0; ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++static SIMPLE_DEV_PM_OPS(hailo_pcie_pm_ops, hailo_pcie_suspend, hailo_pcie_resume); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 16, 0 ) ++static void hailo_pci_reset_prepare(struct pci_dev *pdev) ++{ ++ struct hailo_pcie_board* board = (struct hailo_pcie_board*) pci_get_drvdata(pdev); ++ int err = 0; ++ /* Reset preparation logic goes here */ ++ pci_err(pdev, "Reset preparation for PCI device \n"); ++ ++ if (board) ++ { ++ // lock board to wait for any pending operations and for synchronization with open ++ down(&board->mutex); ++ if (board->vdma.used_by_filp != NULL) { ++ // Try to close all vDMA channels before reset ++ err = hailo_pcie_driver_down(board); ++ if (err < 0) { ++ pci_err(pdev, "Error while trying to call FW to close vdma channels (errno %d)\n", err); ++ } ++ } ++ up(&board->mutex); ++ } ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 16, 0 ) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION( 4, 13, 0 ) && LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 16, 0 ) ++static void hailo_pci_reset_notify(struct pci_dev *pdev, bool prepare) ++{ ++ if (prepare) { ++ hailo_pci_reset_prepare(pdev); ++ } ++} ++#endif ++ ++static const struct pci_error_handlers hailo_pcie_err_handlers = { ++#if LINUX_VERSION_CODE < KERNEL_VERSION( 3, 16, 0 ) ++/* No FLR callback */ ++#elif LINUX_VERSION_CODE < KERNEL_VERSION( 4, 13, 0 ) ++/* FLR Callback is reset_notify */ ++ .reset_notify = hailo_pci_reset_notify, ++#else ++/* FLR Callback is reset_prepare */ ++ .reset_prepare = hailo_pci_reset_prepare, ++#endif ++}; ++ ++static struct pci_device_id hailo_pcie_id_table[] = ++{ ++ {PCI_DEVICE_DATA(HAILO, HAILO8, HAILO_BOARD_TYPE_HAILO8)}, ++ {PCI_DEVICE_DATA(HAILO, HAILO15, HAILO_BOARD_TYPE_HAILO15)}, ++ {PCI_DEVICE_DATA(HAILO, PLUTO, HAILO_BOARD_TYPE_PLUTO)}, ++ {0,0,0,0,0,0,0 }, ++}; ++ ++static struct file_operations hailo_pcie_fops = ++{ ++ owner: THIS_MODULE, ++ unlocked_ioctl: hailo_pcie_fops_unlockedioctl, ++ mmap: hailo_pcie_fops_mmap, ++ open: hailo_pcie_fops_open, ++ release: hailo_pcie_fops_release ++}; ++ ++ ++static struct pci_driver hailo_pci_driver = ++{ ++ name: DRIVER_NAME, ++ id_table: hailo_pcie_id_table, ++ probe: hailo_pcie_probe, ++ remove: hailo_pcie_remove, ++ driver: { ++ pm: &hailo_pcie_pm_ops, ++ }, ++ err_handler: &hailo_pcie_err_handlers, ++}; ++ ++MODULE_DEVICE_TABLE (pci, hailo_pcie_id_table); ++ ++static int hailo_pcie_register_chrdev(unsigned int major, const char *name) ++{ ++ int char_major; ++ ++ char_major = register_chrdev(major, name, &hailo_pcie_fops); ++ ++ chardev_class = class_create_compat("hailo_chardev"); ++ ++ return char_major; ++} ++ ++static void hailo_pcie_unregister_chrdev(unsigned int major, const char *name) ++{ ++ class_destroy(chardev_class); ++ unregister_chrdev(major, name); ++} ++ ++static int __init hailo_pcie_module_init(void) ++{ ++ int err; ++ ++ pr_notice(DRIVER_NAME ": Init module. driver version %s\n", HAILO_DRV_VER); ++ ++ if ( 0 > (char_major = hailo_pcie_register_chrdev(0, DRIVER_NAME)) ) ++ { ++ pr_err(DRIVER_NAME ": Init Error, failed to call register_chrdev.\n"); ++ ++ return char_major; ++ } ++ ++ if ( 0 != (err = pci_register_driver(&hailo_pci_driver))) ++ { ++ pr_err(DRIVER_NAME ": Init Error, failed to call pci_register_driver.\n"); ++ class_destroy(chardev_class); ++ hailo_pcie_unregister_chrdev(char_major, DRIVER_NAME); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void __exit hailo_pcie_module_exit(void) ++{ ++ ++ pr_notice(DRIVER_NAME ": Exit module.\n"); ++ ++ // Unregister the driver from pci bus ++ pci_unregister_driver(&hailo_pci_driver); ++ hailo_pcie_unregister_chrdev(char_major, DRIVER_NAME); ++ ++ pr_notice(DRIVER_NAME ": Hailo PCIe driver unloaded.\n"); ++} ++ ++ ++module_init(hailo_pcie_module_init); ++module_exit(hailo_pcie_module_exit); ++ ++module_param(o_dbg, int, S_IRUGO | S_IWUSR); ++ ++module_param_named(no_power_mode, g_is_power_mode_enabled, invbool, S_IRUGO); ++MODULE_PARM_DESC(no_power_mode, "Disables automatic D0->D3 PCIe transactions"); ++ ++module_param(force_allocation_from_driver, int, S_IRUGO); ++MODULE_PARM_DESC(force_allocation_from_driver, "Determines whether to force buffer allocation from driver or userspace"); ++ ++module_param(force_desc_page_size, int, S_IRUGO); ++MODULE_PARM_DESC(force_desc_page_size, "Determines the maximum DMA descriptor page size (must be a power of 2)"); ++ ++module_param(force_hailo15_legacy_mode, bool, S_IRUGO); ++MODULE_PARM_DESC(force_hailo15_legacy_mode, "Forces work with Hailo15 in legacy mode(relevant for emulators)"); ++ ++MODULE_AUTHOR("Hailo Technologies Ltd."); ++MODULE_DESCRIPTION("Hailo PCIe driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(HAILO_DRV_VER); ++ +diff --git a/drivers/media/pci/hailo/src/pcie.h b/drivers/media/pci/hailo/src/pcie.h +new file mode 100644 +index 000000000000..cfee8be8b820 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/pcie.h +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_PCIE_H_ ++#define _HAILO_PCI_PCIE_H_ ++ ++#include "vdma/vdma.h" ++#include "hailo_ioctl_common.h" ++#include "pcie_common.h" ++#include "utils/fw_common.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct hailo_fw_control_info { ++ // protects that only one fw control will be send at a time ++ struct semaphore mutex; ++ // called from the interrupt handler to notify that a response is ready ++ struct completion completion; ++ // the command we are currently handling ++ struct hailo_fw_control command; ++}; ++ ++struct hailo_pcie_driver_down_info { ++ // called from the interrupt handler to notify that FW completed reset ++ struct completion reset_completed; ++}; ++ ++struct hailo_fw_boot { ++ // the filp that enabled interrupts for fw boot. the interrupt is enabled if this is not null ++ struct file *filp; ++ // called from the interrupt handler to notify that an interrupt was raised ++ struct completion completion; ++}; ++ ++ ++// Context for each open file handle ++// TODO: store board and use as actual context ++struct hailo_file_context { ++ struct list_head open_files_list; ++ struct file *filp; ++ struct hailo_vdma_file_context vdma_context; ++ bool is_valid; ++}; ++ ++struct hailo_pcie_board { ++ struct list_head board_list; ++ struct pci_dev *pDev; ++ u32 board_index; ++ atomic_t ref_count; ++ struct list_head open_files_list; ++ struct hailo_pcie_resources pcie_resources; ++ struct hailo_fw_control_info fw_control; ++ struct hailo_pcie_driver_down_info driver_down; ++ struct semaphore mutex; ++ struct hailo_vdma_controller vdma; ++ spinlock_t notification_read_spinlock; ++ struct list_head notification_wait_list; ++ struct hailo_d2h_notification notification_cache; ++ struct hailo_d2h_notification notification_to_user; ++ struct hailo_memory_transfer_params memory_transfer_params; ++ u32 desc_max_page_size; ++ enum hailo_allocation_mode allocation_mode; ++ struct completion fw_loaded_completion; ++ bool interrupts_enabled; ++ // Only needed in accelerator type soc ++ struct completion soc_connect_accepted; ++}; ++ ++bool power_mode_enabled(void); ++ ++struct hailo_pcie_board* hailo_pcie_get_board_index(u32 index); ++void hailo_disable_interrupts(struct hailo_pcie_board *board); ++int hailo_enable_interrupts(struct hailo_pcie_board *board); ++ ++#endif /* _HAILO_PCI_PCIE_H_ */ ++ +diff --git a/drivers/media/pci/hailo/src/sysfs.c b/drivers/media/pci/hailo/src/sysfs.c +new file mode 100644 +index 000000000000..6b914fb58aea +--- /dev/null ++++ b/drivers/media/pci/hailo/src/sysfs.c +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "sysfs.h" ++#include "pcie.h" ++ ++#include ++#include ++ ++static ssize_t board_location_show(struct device *dev, struct device_attribute *_attr, ++ char *buf) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)dev_get_drvdata(dev); ++ const char *dev_info = pci_name(board->pDev); ++ return sprintf(buf, "%s", dev_info); ++} ++static DEVICE_ATTR_RO(board_location); ++ ++static ssize_t device_id_show(struct device *dev, struct device_attribute *_attr, ++ char *buf) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)dev_get_drvdata(dev); ++ return sprintf(buf, "%x:%x", board->pDev->vendor, board->pDev->device); ++} ++static DEVICE_ATTR_RO(device_id); ++ ++static ssize_t accelerator_type_show(struct device *dev, struct device_attribute *_attr, ++ char *buf) ++{ ++ struct hailo_pcie_board *board = (struct hailo_pcie_board *)dev_get_drvdata(dev); ++ return sprintf(buf, "%d", board->pcie_resources.accelerator_type); ++} ++static DEVICE_ATTR_RO(accelerator_type); ++ ++static struct attribute *hailo_dev_attrs[] = { ++ &dev_attr_board_location.attr, ++ &dev_attr_device_id.attr, ++ &dev_attr_accelerator_type.attr, ++ NULL ++}; ++ ++ATTRIBUTE_GROUPS(hailo_dev); ++const struct attribute_group **g_hailo_dev_groups = hailo_dev_groups; +diff --git a/drivers/media/pci/hailo/src/sysfs.h b/drivers/media/pci/hailo/src/sysfs.h +new file mode 100644 +index 000000000000..eaf9e7231fc4 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/sysfs.h +@@ -0,0 +1,13 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_SYSFS_H_ ++#define _HAILO_PCI_SYSFS_H_ ++ ++#include ++ ++extern const struct attribute_group **g_hailo_dev_groups; ++ ++#endif /* _HAILO_PCI_SYSFS_H_ */ +diff --git a/drivers/media/pci/hailo/src/utils.c b/drivers/media/pci/hailo/src/utils.c +new file mode 100644 +index 000000000000..5f87e2c00e89 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/utils.c +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include ++#include ++#include ++#include ++ ++#include "pcie.h" ++#include "utils.h" ++#include "utils/logs.h" ++ ++ ++void hailo_pcie_clear_notification_wait_list(struct hailo_pcie_board *pBoard, struct file *filp) ++{ ++ struct hailo_notification_wait *cur = NULL, *next = NULL; ++ list_for_each_entry_safe(cur, next, &pBoard->notification_wait_list, notification_wait_list) { ++ if (cur->filp == filp) { ++ list_del_rcu(&cur->notification_wait_list); ++ synchronize_rcu(); ++ kfree(cur); ++ } ++ } ++} +diff --git a/drivers/media/pci/hailo/src/utils.h b/drivers/media/pci/hailo/src/utils.h +new file mode 100644 +index 000000000000..b357150086c7 +--- /dev/null ++++ b/drivers/media/pci/hailo/src/utils.h +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_UTILS_H_ ++#define _HAILO_PCI_UTILS_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pcie.h" ++ ++void hailo_pcie_clear_notification_wait_list(struct hailo_pcie_board *pBoard, struct file *filp); ++ ++#endif /* _HAILO_PCI_UTILS_H_ */ +diff --git a/drivers/media/pci/hailo/utils/compact.h b/drivers/media/pci/hailo/utils/compact.h +new file mode 100644 +index 000000000000..c33967d0c2f2 +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/compact.h +@@ -0,0 +1,153 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_PCI_COMPACT_H_ ++#define _HAILO_PCI_COMPACT_H_ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) ++#define class_create_compat class_create ++#else ++#define class_create_compat(name) class_create(THIS_MODULE, name) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) ++#define pci_printk(level, pdev, fmt, arg...) \ ++ dev_printk(level, &(pdev)->dev, fmt, ##arg) ++#define pci_emerg(pdev, fmt, arg...) dev_emerg(&(pdev)->dev, fmt, ##arg) ++#define pci_alert(pdev, fmt, arg...) dev_alert(&(pdev)->dev, fmt, ##arg) ++#define pci_crit(pdev, fmt, arg...) dev_crit(&(pdev)->dev, fmt, ##arg) ++#define pci_err(pdev, fmt, arg...) dev_err(&(pdev)->dev, fmt, ##arg) ++#define pci_warn(pdev, fmt, arg...) dev_warn(&(pdev)->dev, fmt, ##arg) ++#define pci_notice(pdev, fmt, arg...) dev_notice(&(pdev)->dev, fmt, ##arg) ++#define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg) ++#define pci_dbg(pdev, fmt, arg...) dev_dbg(&(pdev)->dev, fmt, ##arg) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0) ++#define get_user_pages_compact get_user_pages ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) ++#define get_user_pages_compact(start, nr_pages, gup_flags, pages) \ ++ get_user_pages(start, nr_pages, gup_flags, pages, NULL) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) ++#define get_user_pages_compact(start, nr_pages, gup_flags, pages) \ ++ get_user_pages(current, current->mm, start, nr_pages, gup_flags, pages, NULL) ++#else ++static inline long get_user_pages_compact(unsigned long start, unsigned long nr_pages, ++ unsigned int gup_flags, struct page **pages) ++{ ++ int write = !!((gup_flags & FOLL_WRITE) == FOLL_WRITE); ++ int force = !!((gup_flags & FOLL_FORCE) == FOLL_FORCE); ++ return get_user_pages(current, current->mm, start, nr_pages, write, force, ++ pages, NULL); ++} ++#endif ++ ++#ifndef _LINUX_MMAP_LOCK_H ++static inline void mmap_read_lock(struct mm_struct *mm) ++{ ++ down_read(&mm->mmap_sem); ++} ++ ++static inline void mmap_read_unlock(struct mm_struct *mm) ++{ ++ up_read(&mm->mmap_sem); ++} ++#endif /* _LINUX_MMAP_LOCK_H */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) ++#define sg_alloc_table_from_pages_segment_compat __sg_alloc_table_from_pages ++#else ++static inline struct scatterlist *sg_alloc_table_from_pages_segment_compat(struct sg_table *sgt, ++ struct page **pages, unsigned int n_pages, unsigned int offset, ++ unsigned long size, unsigned int max_segment, ++ struct scatterlist *prv, unsigned int left_pages, ++ gfp_t gfp_mask) ++{ ++ int res = 0; ++ ++ if (NULL != prv) { ++ // prv not suported ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (0 != left_pages) { ++ // Left pages not supported ++ return ERR_PTR(-EINVAL); ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) ++ res = sg_alloc_table_from_pages_segment(sgt, pages, n_pages, offset, size, max_segment, gfp_mask); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) ++ res = __sg_alloc_table_from_pages(sgt, pages, n_pages, offset, size, max_segment, gfp_mask); ++#else ++ res = sg_alloc_table_from_pages(sgt, pages, n_pages, offset, size, gfp_mask); ++#endif ++ if (res < 0) { ++ return ERR_PTR(res); ++ } ++ ++ return sgt->sgl; ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 5, 0, 0 ) ++#define compatible_access_ok(a,b,c) access_ok(b, c) ++#else ++#define compatible_access_ok(a,b,c) access_ok(a, b, c) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++#define PCI_DEVICE_DATA(vend, dev, data) \ ++ .vendor = PCI_VENDOR_ID_##vend, .device = PCI_DEVICE_ID_##vend##_##dev, \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \ ++ .driver_data = (kernel_ulong_t)(data) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++// On kernels < 4.1.12, kvmalloc, kvfree is not implemented. For simplicity, instead of implement our own ++// kvmalloc/kvfree, just using vmalloc and vfree (It may reduce allocate/access performance, but it worth it). ++static inline void *kvmalloc_array(size_t n, size_t size, gfp_t flags) ++{ ++ (void)flags; //ignore ++ return vmalloc(n * size); ++} ++ ++#define kvfree vfree ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++static inline bool is_dma_capable(struct device *dev, dma_addr_t dma_addr, size_t size) ++{ ++// Case for Rasberry Pie kernel versions 5.4.83 <=> 5.5.0 - already changed bus_dma_mask -> bus_dma_limit ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) || (defined(HAILO_RASBERRY_PIE) && LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 83)) ++ const u64 bus_dma_limit = dev->bus_dma_limit; ++#else ++ const u64 bus_dma_limit = dev->bus_dma_mask; ++#endif ++ ++ return (dma_addr <= min_not_zero(*dev->dma_mask, bus_dma_limit)); ++} ++#else ++static inline bool is_dma_capable(struct device *dev, dma_addr_t dma_addr, size_t size) ++{ ++ // Implementation of dma_capable from linux kernel ++ const u64 bus_dma_limit = (*dev->dma_mask + 1) & ~(*dev->dma_mask); ++ if (bus_dma_limit && size > bus_dma_limit) { ++ return false; ++ } ++ ++ if ((dma_addr | (dma_addr + size - 1)) & ~(*dev->dma_mask)) { ++ return false; ++ } ++ ++ return true; ++} ++#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ ++#endif /* _HAILO_PCI_COMPACT_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/utils/fw_common.h b/drivers/media/pci/hailo/utils/fw_common.h +new file mode 100644 +index 000000000000..713b180acc66 +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/fw_common.h +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_LINUX_COMMON_H_ ++#define _HAILO_LINUX_COMMON_H_ ++ ++#include "hailo_ioctl_common.h" ++ ++struct hailo_notification_wait { ++ struct list_head notification_wait_list; ++ int tgid; ++ struct file* filp; ++ struct completion notification_completion; ++ bool is_disabled; ++}; ++ ++#endif /* _HAILO_LINUX_COMMON_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/utils/integrated_nnc_utils.c b/drivers/media/pci/hailo/utils/integrated_nnc_utils.c +new file mode 100755 +index 000000000000..599e740b3b1c +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/integrated_nnc_utils.c +@@ -0,0 +1,101 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "integrated_nnc_utils.h" ++#include "utils/logs.h" ++ ++#include ++#include ++#include ++#include ++ ++int hailo_ioremap_resource(struct platform_device *pdev, struct hailo_resource *resource, ++ const char *name) ++{ ++ void __iomem *address; ++ struct resource *platform_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); ++ if (NULL == platform_resource) { ++ return -ENOENT; ++ } ++ ++ address = devm_ioremap_resource(&pdev->dev, platform_resource); ++ if (IS_ERR(address)) { ++ return PTR_ERR(address); ++ } ++ ++ resource->address = (uintptr_t)address; ++ resource->size = resource_size(platform_resource); ++ ++ hailo_dev_dbg(&pdev->dev, "resource[%s]: remap %pr of %zx bytes to virtual start address %lx\n", ++ platform_resource->name, platform_resource, resource->size, (uintptr_t)address); ++ ++ return 0; ++} ++ ++// TODO: HRT-8475 - change to name instead of index ++int hailo_ioremap_shmem(struct platform_device *pdev, int index, struct hailo_resource *resource) ++{ ++ int ret; ++ struct resource res; ++ struct device_node *shmem; ++ void __iomem * remap_ptr; ++ ++ shmem = of_parse_phandle(pdev->dev.of_node, "shmem", index); ++ ret = of_address_to_resource(shmem, 0, &res); ++ if (ret) { ++ hailo_dev_err(&pdev->dev, "hailo_ioremap_shmem, failed to get memory (index: %d)\n", index); ++ return ret; ++ } ++ of_node_put(shmem); ++ ++ remap_ptr = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); ++ if (!remap_ptr) { ++ hailo_dev_err(&pdev->dev, "hailo_ioremap_shmem, failed to ioremap shmem (index: %d)\n", index); ++ return -EADDRNOTAVAIL; ++ } ++ ++ resource->address = (uintptr_t)remap_ptr; ++ resource->size = resource_size(&res); ++ ++ return 0; ++} ++ ++int direct_memory_transfer(struct platform_device *pdev, struct hailo_memory_transfer_params *params) ++{ ++ int err = -EINVAL; ++ void __iomem *mem = ioremap(params->address, params->count); ++ if (NULL == mem) { ++ hailo_dev_err(&pdev->dev, "Failed ioremap %llu %zu\n", params->address, params->count); ++ return -ENOMEM; ++ } ++ ++ switch (params->transfer_direction) { ++ case TRANSFER_READ: ++ memcpy_fromio(params->buffer, mem, params->count); ++ err = 0; ++ break; ++ case TRANSFER_WRITE: ++ memcpy_toio(mem, params->buffer, params->count); ++ err = 0; ++ break; ++ default: ++ hailo_dev_err(&pdev->dev, "Invalid transfer direction %d\n", (int)params->transfer_direction); ++ err = -EINVAL; ++ } ++ ++ iounmap(mem); ++ return err; ++} ++ ++int hailo_get_resource_physical_addr(struct platform_device *pdev, const char *name, u64 *address) ++{ ++ struct resource *platform_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); ++ if (NULL == platform_resource) { ++ return -ENOENT; ++ } ++ ++ *address = (u64)(platform_resource->start); ++ return 0; ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/utils/integrated_nnc_utils.h b/drivers/media/pci/hailo/utils/integrated_nnc_utils.h +new file mode 100755 +index 000000000000..8995f44fef95 +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/integrated_nnc_utils.h +@@ -0,0 +1,30 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _INTEGRATED_NNC_UTILS_H_ ++#define _INTEGRATED_NNC_UTILS_H_ ++ ++#include ++#include "hailo_resource.h" ++ ++#define HAILO15_CORE_CONTROL_MAILBOX_INDEX (0) ++#define HAILO15_CORE_NOTIFICATION_MAILBOX_INDEX (1) ++#define HAILO15_CORE_DRIVER_DOWN_MAILBOX_INDEX (2) ++ ++#define HAILO15_CORE_CONTROL_MAILBOX_TX_SHMEM_INDEX (0) ++#define HAILO15_CORE_CONTROL_MAILBOX_RX_SHMEM_INDEX (1) ++#define HAILO15_CORE_NOTIFICATION_MAILBOX_RX_SHMEM_INDEX (2) ++ ++int hailo_ioremap_resource(struct platform_device *pdev, struct hailo_resource *resource, ++ const char *name); ++ ++// TODO: HRT-8475 - change to name instead of index ++int hailo_ioremap_shmem(struct platform_device *pdev, int index, struct hailo_resource *resource); ++ ++int direct_memory_transfer(struct platform_device *pDev, struct hailo_memory_transfer_params *params); ++ ++int hailo_get_resource_physical_addr(struct platform_device *pdev, const char *name, u64 *address); ++ ++#endif /* _INTEGRATED_NNC_UTILS_H_ */ +diff --git a/drivers/media/pci/hailo/utils/logs.c b/drivers/media/pci/hailo/utils/logs.c +new file mode 100644 +index 000000000000..a215d3ddda41 +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/logs.c +@@ -0,0 +1,8 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "logs.h" ++ ++int o_dbg = LOGLEVEL_NOTICE; +diff --git a/drivers/media/pci/hailo/utils/logs.h b/drivers/media/pci/hailo/utils/logs.h +new file mode 100644 +index 000000000000..4179ef439003 +--- /dev/null ++++ b/drivers/media/pci/hailo/utils/logs.h +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _COMMON_LOGS_H_ ++#define _COMMON_LOGS_H_ ++ ++#include ++ ++// Should be used only by "module_param". ++// Specify the current debug level for the logs ++extern int o_dbg; ++ ++ ++// Logging, same interface as dev_*, uses o_dbg to filter ++// log messages ++#define hailo_printk(level, dev, fmt, ...) \ ++ do { \ ++ int __level = (level[1] - '0'); \ ++ if (__level <= o_dbg) { \ ++ dev_printk((level), dev, fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define hailo_emerg(board, fmt, ...) hailo_printk(KERN_EMERG, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_alert(board, fmt, ...) hailo_printk(KERN_ALERT, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_crit(board, fmt, ...) hailo_printk(KERN_CRIT, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_err(board, fmt, ...) hailo_printk(KERN_ERR, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_warn(board, fmt, ...) hailo_printk(KERN_WARNING, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_notice(board, fmt, ...) hailo_printk(KERN_NOTICE, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_info(board, fmt, ...) hailo_printk(KERN_INFO, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++#define hailo_dbg(board, fmt, ...) hailo_printk(KERN_DEBUG, &(board)->pDev->dev, fmt, ##__VA_ARGS__) ++ ++#define hailo_dev_emerg(dev, fmt, ...) hailo_printk(KERN_EMERG, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_alert(dev, fmt, ...) hailo_printk(KERN_ALERT, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_crit(dev, fmt, ...) hailo_printk(KERN_CRIT, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_err(dev, fmt, ...) hailo_printk(KERN_ERR, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_warn(dev, fmt, ...) hailo_printk(KERN_WARNING, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_notice(dev, fmt, ...) hailo_printk(KERN_NOTICE, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_info(dev, fmt, ...) hailo_printk(KERN_INFO, dev, fmt, ##__VA_ARGS__) ++#define hailo_dev_dbg(dev, fmt, ...) hailo_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__) ++ ++ ++#endif //_COMMON_LOGS_H_ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/vdma/ioctl.c b/drivers/media/pci/hailo/vdma/ioctl.c +new file mode 100644 +index 000000000000..2b29e2461509 +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/ioctl.c +@@ -0,0 +1,715 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#include "ioctl.h" ++#include "memory.h" ++#include "utils/logs.h" ++#include "utils.h" ++ ++#include ++#include ++ ++ ++long hailo_vdma_enable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_vdma_enable_channels_params input; ++ struct hailo_vdma_engine *engine = NULL; ++ u8 engine_index = 0; ++ u32 channels_bitmap = 0; ++ ++ if (copy_from_user(&input, (void *)arg, sizeof(input))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ // Validate params (ignoring engine_index >= controller->vdma_engines_count). ++ for_each_vdma_engine(controller, engine, engine_index) { ++ channels_bitmap = input.channels_bitmap_per_engine[engine_index]; ++ if (0 != (channels_bitmap & engine->enabled_channels)) { ++ hailo_dev_err(controller->dev, "Trying to enable channels that are already enabled\n"); ++ return -EINVAL; ++ } ++ } ++ ++ for_each_vdma_engine(controller, engine, engine_index) { ++ channels_bitmap = input.channels_bitmap_per_engine[engine_index]; ++ hailo_vdma_engine_enable_channels(engine, channels_bitmap, ++ input.enable_timestamps_measure); ++ hailo_vdma_update_interrupts_mask(controller, engine_index); ++ hailo_dev_info(controller->dev, "Enabled interrupts for engine %u, channels bitmap 0x%x\n", ++ engine_index, channels_bitmap); ++ } ++ ++ return 0; ++} ++ ++long hailo_vdma_disable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_vdma_disable_channels_params input; ++ struct hailo_vdma_engine *engine = NULL; ++ u8 engine_index = 0; ++ u32 channels_bitmap = 0; ++ unsigned long irq_saved_flags = 0; ++ ++ if (copy_from_user(&input, (void*)arg, sizeof(input))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ // Validate params (ignoring engine_index >= controller->vdma_engines_count). ++ for_each_vdma_engine(controller, engine, engine_index) { ++ channels_bitmap = input.channels_bitmap_per_engine[engine_index]; ++ if (channels_bitmap != (channels_bitmap & engine->enabled_channels)) { ++ hailo_dev_warn(controller->dev, "Trying to disable channels that were not enabled\n"); ++ } ++ } ++ ++ for_each_vdma_engine(controller, engine, engine_index) { ++ channels_bitmap = input.channels_bitmap_per_engine[engine_index]; ++ hailo_vdma_engine_disable_channels(engine, channels_bitmap); ++ hailo_vdma_update_interrupts_mask(controller, engine_index); ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ hailo_vdma_engine_clear_channel_interrupts(engine, channels_bitmap); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); ++ ++ hailo_dev_info(controller->dev, "Disabled channels for engine %u, bitmap 0x%x\n", ++ engine_index, channels_bitmap); ++ } ++ ++ // Wake up threads waiting ++ wake_up_interruptible_all(&controller->interrupts_wq); ++ ++ return 0; ++} ++ ++static bool got_interrupt(struct hailo_vdma_controller *controller, ++ u32 channels_bitmap_per_engine[MAX_VDMA_ENGINES]) ++{ ++ struct hailo_vdma_engine *engine = NULL; ++ u8 engine_index = 0; ++ for_each_vdma_engine(controller, engine, engine_index) { ++ if (hailo_vdma_engine_got_interrupt(engine, ++ channels_bitmap_per_engine[engine_index])) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++static void transfer_done(struct hailo_ongoing_transfer *transfer, void *opaque) ++{ ++ u8 i = 0; ++ struct hailo_vdma_controller *controller = (struct hailo_vdma_controller *)opaque; ++ for (i = 0; i < transfer->buffers_count; i++) { ++ struct hailo_vdma_buffer *mapped_buffer = (struct hailo_vdma_buffer *)transfer->buffers[i].opaque; ++ hailo_vdma_buffer_sync_cyclic(controller, mapped_buffer, HAILO_SYNC_FOR_CPU, ++ transfer->buffers[i].offset, transfer->buffers[i].size); ++ } ++} ++ ++long hailo_vdma_interrupts_wait_ioctl(struct hailo_vdma_controller *controller, unsigned long arg, ++ struct semaphore *mutex, bool *should_up_board_mutex) ++{ ++ long err = 0; ++ struct hailo_vdma_interrupts_wait_params params = {0}; ++ struct hailo_vdma_engine *engine = NULL; ++ bool bitmap_not_empty = false; ++ u8 engine_index = 0; ++ u32 irq_bitmap = 0; ++ unsigned long irq_saved_flags = 0; ++ ++ if (copy_from_user(¶ms, (void*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "HAILO_VDMA_INTERRUPTS_WAIT, copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ // We don't need to validate that channels_bitmap_per_engine are enabled - ++ // If the channel is not enabled we just return an empty interrupts list. ++ ++ // Validate params (ignoring engine_index >= controller->vdma_engines_count). ++ // It us ok to wait on a disabled channel - the wait will just exit. ++ for_each_vdma_engine(controller, engine, engine_index) { ++ if (0 != params.channels_bitmap_per_engine[engine_index]) { ++ bitmap_not_empty = true; ++ } ++ } ++ if (!bitmap_not_empty) { ++ hailo_dev_err(controller->dev, "Got an empty bitmap for wait interrupts\n"); ++ return -EINVAL; ++ } ++ ++ up(mutex); ++ err = wait_event_interruptible(controller->interrupts_wq, ++ got_interrupt(controller, params.channels_bitmap_per_engine)); ++ if (err < 0) { ++ hailo_dev_info(controller->dev, ++ "wait channel interrupts failed with err=%ld (process was interrupted or killed)\n", err); ++ *should_up_board_mutex = false; ++ return err; ++ } ++ ++ if (down_interruptible(mutex)) { ++ hailo_dev_info(controller->dev, "down_interruptible error (process was interrupted or killed)\n"); ++ *should_up_board_mutex = false; ++ return -ERESTARTSYS; ++ } ++ ++ params.channels_count = 0; ++ for_each_vdma_engine(controller, engine, engine_index) { ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ irq_bitmap = hailo_vdma_engine_read_interrupts(engine, ++ params.channels_bitmap_per_engine[engine->index]); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); ++ ++ err = hailo_vdma_engine_fill_irq_data(¶ms, engine, irq_bitmap, ++ transfer_done, controller); ++ if (err < 0) { ++ hailo_dev_err(controller->dev, "Failed fill irq data %ld", err); ++ return err; ++ } ++ } ++ ++ if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static uintptr_t hailo_get_next_vdma_handle(struct hailo_vdma_file_context *context) ++{ ++ // Note: The kernel code left-shifts the 'offset' param from the user-space call to mmap by PAGE_SHIFT bits and ++ // stores the result in 'vm_area_struct.vm_pgoff'. We pass the desc_handle to mmap in the offset param. To ++ // counter this, we right-shift the desc_handle. See also 'mmap function'. ++ uintptr_t next_handle = 0; ++ next_handle = atomic_inc_return(&context->last_vdma_handle); ++ return (next_handle << PAGE_SHIFT); ++} ++ ++long hailo_vdma_buffer_map_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_vdma_buffer_map_params buf_info; ++ struct hailo_vdma_buffer *mapped_buffer = NULL; ++ enum dma_data_direction direction = DMA_NONE; ++ struct hailo_vdma_low_memory_buffer *low_memory_buffer = NULL; ++ ++ if (copy_from_user(&buf_info, (void __user*)arg, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ hailo_dev_info(controller->dev, "address %lx tgid %d size: %zu\n", ++ buf_info.user_address, current->tgid, buf_info.size); ++ ++ direction = get_dma_direction(buf_info.data_direction); ++ if (DMA_NONE == direction) { ++ hailo_dev_err(controller->dev, "invalid data direction %d\n", buf_info.data_direction); ++ return -EINVAL; ++ } ++ ++ low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, buf_info.allocated_buffer_handle); ++ ++ mapped_buffer = hailo_vdma_buffer_map(controller->dev, ++ buf_info.user_address, buf_info.size, direction, buf_info.buffer_type, low_memory_buffer); ++ if (IS_ERR(mapped_buffer)) { ++ hailo_dev_err(controller->dev, "failed map buffer %lx\n", buf_info.user_address); ++ return PTR_ERR(mapped_buffer); ++ } ++ ++ mapped_buffer->handle = atomic_inc_return(&context->last_vdma_user_buffer_handle); ++ buf_info.mapped_handle = mapped_buffer->handle; ++ if (copy_to_user((void __user*)arg, &buf_info, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ hailo_vdma_buffer_put(mapped_buffer); ++ return -EFAULT; ++ } ++ ++ list_add(&mapped_buffer->mapped_user_buffer_list, &context->mapped_user_buffer_list); ++ hailo_dev_info(controller->dev, "buffer %lx (handle %zu) is mapped\n", ++ buf_info.user_address, buf_info.mapped_handle); ++ return 0; ++} ++ ++long hailo_vdma_buffer_unmap_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_vdma_buffer *mapped_buffer = NULL; ++ struct hailo_vdma_buffer_unmap_params buffer_unmap_params; ++ ++ if (copy_from_user(&buffer_unmap_params, (void __user*)arg, sizeof(buffer_unmap_params))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ hailo_dev_info(controller->dev, "unmap user buffer handle %zu\n", buffer_unmap_params.mapped_handle); ++ ++ mapped_buffer = hailo_vdma_find_mapped_user_buffer(context, buffer_unmap_params.mapped_handle); ++ if (mapped_buffer == NULL) { ++ hailo_dev_warn(controller->dev, "buffer handle %zu not found\n", buffer_unmap_params.mapped_handle); ++ return -EINVAL; ++ } ++ ++ list_del(&mapped_buffer->mapped_user_buffer_list); ++ hailo_vdma_buffer_put(mapped_buffer); ++ return 0; ++} ++ ++long hailo_vdma_buffer_sync_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_vdma_buffer_sync_params sync_info = {}; ++ struct hailo_vdma_buffer *mapped_buffer = NULL; ++ ++ if (copy_from_user(&sync_info, (void __user*)arg, sizeof(sync_info))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -EFAULT; ++ } ++ ++ if (!(mapped_buffer = hailo_vdma_find_mapped_user_buffer(context, sync_info.handle))) { ++ hailo_dev_err(controller->dev, "buffer handle %zu doesn't exist\n", sync_info.handle); ++ return -EINVAL; ++ } ++ ++ if ((sync_info.sync_type != HAILO_SYNC_FOR_CPU) && (sync_info.sync_type != HAILO_SYNC_FOR_DEVICE)) { ++ hailo_dev_err(controller->dev, "Invalid sync_type given for vdma buffer sync.\n"); ++ return -EINVAL; ++ } ++ ++ if (sync_info.offset + sync_info.count > mapped_buffer->size) { ++ hailo_dev_err(controller->dev, "Invalid offset/count given for vdma buffer sync. offset %zu count %zu buffer size %u\n", ++ sync_info.offset, sync_info.count, mapped_buffer->size); ++ return -EINVAL; ++ } ++ ++ hailo_vdma_buffer_sync(controller, mapped_buffer, sync_info.sync_type, ++ sync_info.offset, sync_info.count); ++ return 0; ++} ++ ++long hailo_desc_list_create_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_desc_list_create_params params; ++ struct hailo_descriptors_list_buffer *descriptors_buffer = NULL; ++ uintptr_t next_handle = 0; ++ long err = -EINVAL; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -EFAULT; ++ } ++ ++ if (params.is_circular && !is_powerof2(params.desc_count)) { ++ hailo_dev_err(controller->dev, "Invalid desc count given : %zu , circular descriptors count must be power of 2\n", ++ params.desc_count); ++ return -EINVAL; ++ } ++ ++ if (!is_powerof2(params.desc_page_size)) { ++ hailo_dev_err(controller->dev, "Invalid desc page size given : %u\n", ++ params.desc_page_size); ++ return -EINVAL; ++ } ++ ++ hailo_dev_info(controller->dev, ++ "Create desc list desc_count: %zu desc_page_size: %u\n", ++ params.desc_count, params.desc_page_size); ++ ++ descriptors_buffer = kzalloc(sizeof(*descriptors_buffer), GFP_KERNEL); ++ if (NULL == descriptors_buffer) { ++ hailo_dev_err(controller->dev, "Failed to allocate buffer for descriptors list struct\n"); ++ return -ENOMEM; ++ } ++ ++ next_handle = hailo_get_next_vdma_handle(context); ++ ++ err = hailo_desc_list_create(controller->dev, params.desc_count, ++ params.desc_page_size, next_handle, params.is_circular, ++ descriptors_buffer); ++ if (err < 0) { ++ hailo_dev_err(controller->dev, "failed to allocate descriptors buffer\n"); ++ kfree(descriptors_buffer); ++ return err; ++ } ++ ++ list_add(&descriptors_buffer->descriptors_buffer_list, &context->descriptors_buffer_list); ++ ++ // Note: The physical address is required for CONTEXT_SWITCH firmware controls ++ BUILD_BUG_ON(sizeof(params.dma_address) < sizeof(descriptors_buffer->dma_address)); ++ params.dma_address = descriptors_buffer->dma_address; ++ params.desc_handle = descriptors_buffer->handle; ++ ++ if(copy_to_user((void __user*)arg, ¶ms, sizeof(params))){ ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ list_del(&descriptors_buffer->descriptors_buffer_list); ++ hailo_desc_list_release(controller->dev, descriptors_buffer); ++ kfree(descriptors_buffer); ++ return -EFAULT; ++ } ++ ++ hailo_dev_info(controller->dev, "Created desc list, handle 0x%llu\n", ++ (u64)params.desc_handle); ++ return 0; ++} ++ ++long hailo_desc_list_release_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_desc_list_release_params params; ++ struct hailo_descriptors_list_buffer *descriptors_buffer = NULL; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -EFAULT; ++ } ++ ++ descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.desc_handle); ++ if (descriptors_buffer == NULL) { ++ hailo_dev_warn(controller->dev, "not found desc handle %llu\n", (unsigned long long)params.desc_handle); ++ return -EINVAL; ++ } ++ ++ list_del(&descriptors_buffer->descriptors_buffer_list); ++ hailo_desc_list_release(controller->dev, descriptors_buffer); ++ kfree(descriptors_buffer); ++ return 0; ++} ++ ++long hailo_desc_list_program_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_desc_list_program_params configure_info; ++ struct hailo_vdma_buffer *mapped_buffer = NULL; ++ struct hailo_descriptors_list_buffer *descriptors_buffer = NULL; ++ struct hailo_vdma_mapped_transfer_buffer transfer_buffer = {0}; ++ ++ if (copy_from_user(&configure_info, (void __user*)arg, sizeof(configure_info))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ hailo_dev_info(controller->dev, "config buffer_handle=%zu desc_handle=%llu starting_desc=%u\n", ++ configure_info.buffer_handle, (u64)configure_info.desc_handle, configure_info.starting_desc); ++ ++ mapped_buffer = hailo_vdma_find_mapped_user_buffer(context, configure_info.buffer_handle); ++ descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, configure_info.desc_handle); ++ if (mapped_buffer == NULL || descriptors_buffer == NULL) { ++ hailo_dev_err(controller->dev, "invalid user/descriptors buffer\n"); ++ return -EFAULT; ++ } ++ ++ if (configure_info.buffer_size > mapped_buffer->size) { ++ hailo_dev_err(controller->dev, "invalid buffer size. \n"); ++ return -EFAULT; ++ } ++ ++ transfer_buffer.sg_table = &mapped_buffer->sg_table; ++ transfer_buffer.size = configure_info.buffer_size; ++ transfer_buffer.offset = configure_info.buffer_offset; ++ ++ return hailo_vdma_program_descriptors_list( ++ controller->hw, ++ &descriptors_buffer->desc_list, ++ configure_info.starting_desc, ++ &transfer_buffer, ++ configure_info.should_bind, ++ configure_info.channel_index, ++ configure_info.last_interrupts_domain, ++ configure_info.is_debug ++ ); ++} ++ ++long hailo_vdma_low_memory_buffer_alloc_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_allocate_low_memory_buffer_params buf_info = {0}; ++ struct hailo_vdma_low_memory_buffer *low_memory_buffer = NULL; ++ long err = -EINVAL; ++ ++ if (copy_from_user(&buf_info, (void __user*)arg, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ low_memory_buffer = kzalloc(sizeof(*low_memory_buffer), GFP_KERNEL); ++ if (NULL == low_memory_buffer) { ++ hailo_dev_err(controller->dev, "memory alloc failed\n"); ++ return -ENOMEM; ++ } ++ ++ err = hailo_vdma_low_memory_buffer_alloc(buf_info.buffer_size, low_memory_buffer); ++ if (err < 0) { ++ kfree(low_memory_buffer); ++ hailo_dev_err(controller->dev, "failed allocating buffer from driver\n"); ++ return err; ++ } ++ ++ // Get handle for allocated buffer ++ low_memory_buffer->handle = hailo_get_next_vdma_handle(context); ++ ++ list_add(&low_memory_buffer->vdma_low_memory_buffer_list, &context->vdma_low_memory_buffer_list); ++ ++ buf_info.buffer_handle = low_memory_buffer->handle; ++ if (copy_to_user((void __user*)arg, &buf_info, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ list_del(&low_memory_buffer->vdma_low_memory_buffer_list); ++ hailo_vdma_low_memory_buffer_free(low_memory_buffer); ++ kfree(low_memory_buffer); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++long hailo_vdma_low_memory_buffer_free_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_vdma_low_memory_buffer *low_memory_buffer = NULL; ++ struct hailo_free_low_memory_buffer_params params = {0}; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, params.buffer_handle); ++ if (NULL == low_memory_buffer) { ++ hailo_dev_warn(controller->dev, "vdma buffer handle %lx not found\n", params.buffer_handle); ++ return -EINVAL; ++ } ++ ++ list_del(&low_memory_buffer->vdma_low_memory_buffer_list); ++ hailo_vdma_low_memory_buffer_free(low_memory_buffer); ++ kfree(low_memory_buffer); ++ return 0; ++} ++ ++long hailo_mark_as_in_use(struct hailo_vdma_controller *controller, unsigned long arg, struct file *filp) ++{ ++ struct hailo_mark_as_in_use_params params = {0}; ++ ++ // If device is used by this FD, return false to indicate its free for usage ++ if (filp == controller->used_by_filp) { ++ params.in_use = false; ++ } else if (NULL != controller->used_by_filp) { ++ params.in_use = true; ++ } else { ++ controller->used_by_filp = filp; ++ params.in_use = false; ++ } ++ ++ if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++long hailo_vdma_continuous_buffer_alloc_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_allocate_continuous_buffer_params buf_info = {0}; ++ struct hailo_vdma_continuous_buffer *continuous_buffer = NULL; ++ long err = -EINVAL; ++ size_t aligned_buffer_size = 0; ++ ++ if (copy_from_user(&buf_info, (void __user*)arg, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ continuous_buffer = kzalloc(sizeof(*continuous_buffer), GFP_KERNEL); ++ if (NULL == continuous_buffer) { ++ hailo_dev_err(controller->dev, "memory alloc failed\n"); ++ return -ENOMEM; ++ } ++ ++ // We use PAGE_ALIGN to support mmap ++ aligned_buffer_size = PAGE_ALIGN(buf_info.buffer_size); ++ err = hailo_vdma_continuous_buffer_alloc(controller->dev, aligned_buffer_size, continuous_buffer); ++ if (err < 0) { ++ kfree(continuous_buffer); ++ return err; ++ } ++ ++ continuous_buffer->handle = hailo_get_next_vdma_handle(context); ++ list_add(&continuous_buffer->continuous_buffer_list, &context->continuous_buffer_list); ++ ++ buf_info.buffer_handle = continuous_buffer->handle; ++ buf_info.dma_address = continuous_buffer->dma_address; ++ if (copy_to_user((void __user*)arg, &buf_info, sizeof(buf_info))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ list_del(&continuous_buffer->continuous_buffer_list); ++ hailo_vdma_continuous_buffer_free(controller->dev, continuous_buffer); ++ kfree(continuous_buffer); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++long hailo_vdma_continuous_buffer_free_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_free_continuous_buffer_params params; ++ struct hailo_vdma_continuous_buffer *continuous_buffer = NULL; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ continuous_buffer = hailo_vdma_find_continuous_buffer(context, params.buffer_handle); ++ if (NULL == continuous_buffer) { ++ hailo_dev_warn(controller->dev, "vdma buffer handle %lx not found\n", params.buffer_handle); ++ return -EINVAL; ++ } ++ ++ list_del(&continuous_buffer->continuous_buffer_list); ++ hailo_vdma_continuous_buffer_free(controller->dev, continuous_buffer); ++ kfree(continuous_buffer); ++ return 0; ++} ++ ++long hailo_vdma_interrupts_read_timestamps_ioctl(struct hailo_vdma_controller *controller, unsigned long arg) ++{ ++ struct hailo_vdma_interrupts_read_timestamp_params *params = &controller->read_interrupt_timestamps_params; ++ struct hailo_vdma_engine *engine = NULL; ++ int err = -EINVAL; ++ ++ hailo_dev_dbg(controller->dev, "Start read interrupt timestamps ioctl\n"); ++ ++ if (copy_from_user(params, (void __user*)arg, sizeof(*params))) { ++ hailo_dev_err(controller->dev, "copy_from_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ if (params->engine_index >= controller->vdma_engines_count) { ++ hailo_dev_err(controller->dev, "Invalid engine %u", params->engine_index); ++ return -EINVAL; ++ } ++ engine = &controller->vdma_engines[params->engine_index]; ++ ++ err = hailo_vdma_engine_read_timestamps(engine, params); ++ if (err < 0) { ++ hailo_dev_err(controller->dev, "Failed read engine interrupts for %u:%u", ++ params->engine_index, params->channel_index); ++ return err; ++ } ++ ++ if (copy_to_user((void __user*)arg, params, sizeof(*params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++long hailo_vdma_launch_transfer_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg) ++{ ++ struct hailo_vdma_launch_transfer_params params; ++ struct hailo_vdma_engine *engine = NULL; ++ struct hailo_vdma_channel *channel = NULL; ++ struct hailo_descriptors_list_buffer *descriptors_buffer = NULL; ++ struct hailo_vdma_mapped_transfer_buffer mapped_transfer_buffers[ARRAY_SIZE(params.buffers)] = {0}; ++ int ret = -EINVAL; ++ u8 i = 0; ++ ++ if (copy_from_user(¶ms, (void __user*)arg, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy from user fail\n"); ++ return -EFAULT; ++ } ++ ++ if (params.engine_index >= controller->vdma_engines_count) { ++ hailo_dev_err(controller->dev, "Invalid engine %u", params.engine_index); ++ return -EINVAL; ++ } ++ engine = &controller->vdma_engines[params.engine_index]; ++ ++ if (params.channel_index >= ARRAY_SIZE(engine->channels)) { ++ hailo_dev_err(controller->dev, "Invalid channel %u", params.channel_index); ++ return -EINVAL; ++ } ++ channel = &engine->channels[params.channel_index]; ++ ++ if (params.buffers_count > ARRAY_SIZE(params.buffers)) { ++ hailo_dev_err(controller->dev, "too many buffers %u\n", params.buffers_count); ++ return -EINVAL; ++ } ++ ++ descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, params.desc_handle); ++ if (descriptors_buffer == NULL) { ++ hailo_dev_err(controller->dev, "invalid descriptors list handle\n"); ++ return -EFAULT; ++ } ++ ++ for (i = 0; i < params.buffers_count; i++) { ++ struct hailo_vdma_buffer *mapped_buffer = ++ hailo_vdma_find_mapped_user_buffer(context, params.buffers[i].mapped_buffer_handle); ++ if (mapped_buffer == NULL) { ++ hailo_dev_err(controller->dev, "invalid user buffer\n"); ++ return -EFAULT; ++ } ++ ++ if (params.buffers[i].size > mapped_buffer->size) { ++ hailo_dev_err(controller->dev, "Syncing size %u while buffer size is %u\n", ++ params.buffers[i].size, mapped_buffer->size); ++ return -EINVAL; ++ } ++ ++ if (params.buffers[i].offset > mapped_buffer->size) { ++ hailo_dev_err(controller->dev, "Syncing offset %u while buffer size is %u\n", ++ params.buffers[i].offset, mapped_buffer->size); ++ return -EINVAL; ++ } ++ ++ // Syncing the buffer to device change its ownership from host to the device. ++ // We sync on D2H as well if the user owns the buffer since the buffer might have been changed by ++ // the host between the time it was mapped and the current async transfer. ++ hailo_vdma_buffer_sync_cyclic(controller, mapped_buffer, HAILO_SYNC_FOR_DEVICE, ++ params.buffers[i].offset, params.buffers[i].size); ++ ++ mapped_transfer_buffers[i].sg_table = &mapped_buffer->sg_table; ++ mapped_transfer_buffers[i].size = params.buffers[i].size; ++ mapped_transfer_buffers[i].offset = params.buffers[i].offset; ++ mapped_transfer_buffers[i].opaque = mapped_buffer; ++ } ++ ++ ret = hailo_vdma_launch_transfer( ++ controller->hw, ++ channel, ++ &descriptors_buffer->desc_list, ++ params.starting_desc, ++ params.buffers_count, ++ mapped_transfer_buffers, ++ params.should_bind, ++ params.first_interrupts_domain, ++ params.last_interrupts_domain, ++ params.is_debug ++ ); ++ if (ret < 0) { ++ params.launch_transfer_status = ret; ++ if (-ECONNRESET != ret) { ++ hailo_dev_err(controller->dev, "Failed launch transfer %d\n", ret); ++ } ++ // Still need to copy fail status back to userspace - success oriented ++ if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ } ++ return ret; ++ } ++ ++ params.descs_programed = ret; ++ params.launch_transfer_status = 0; ++ ++ if (copy_to_user((void __user*)arg, ¶ms, sizeof(params))) { ++ hailo_dev_err(controller->dev, "copy_to_user fail\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/vdma/ioctl.h b/drivers/media/pci/hailo/vdma/ioctl.h +new file mode 100644 +index 000000000000..d2b480d2d422 +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/ioctl.h +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#ifndef _HAILO_VDMA_IOCTL_H_ ++#define _HAILO_VDMA_IOCTL_H_ ++ ++#include "vdma/vdma.h" ++ ++long hailo_vdma_enable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_disable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_interrupts_wait_ioctl(struct hailo_vdma_controller *controller, unsigned long arg, ++ struct semaphore *mutex, bool *should_up_board_mutex); ++ ++long hailo_vdma_buffer_map_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_buffer_unmap_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long handle); ++long hailo_vdma_buffer_sync_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++long hailo_desc_list_create_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_desc_list_release_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_desc_list_program_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++long hailo_vdma_low_memory_buffer_alloc_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_low_memory_buffer_free_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++long hailo_mark_as_in_use(struct hailo_vdma_controller *controller, unsigned long arg, struct file *filp); ++ ++long hailo_vdma_continuous_buffer_alloc_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++long hailo_vdma_continuous_buffer_free_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, unsigned long arg); ++ ++long hailo_vdma_interrupts_read_timestamps_ioctl(struct hailo_vdma_controller *controller, unsigned long arg); ++ ++long hailo_vdma_launch_transfer_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned long arg); ++ ++#endif /* _HAILO_VDMA_IOCTL_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/vdma/memory.c b/drivers/media/pci/hailo/vdma/memory.c +new file mode 100644 +index 000000000000..b06de38579fb +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/memory.c +@@ -0,0 +1,661 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#define pr_fmt(fmt) "hailo: " fmt ++ ++#include "memory.h" ++#include "utils/compact.h" ++ ++#include ++#include ++#include ++#include ++ ++ ++#define SGL_MAX_SEGMENT_SIZE (0x10000) ++// See linux/mm.h ++#define MMIO_AND_NO_PAGES_VMA_MASK (VM_IO | VM_PFNMAP) ++ ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, ++ struct sg_table *sgt); ++static int prepare_sg_table(struct sg_table *sg_table, uintptr_t user_address, u32 size, ++ struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer); ++static void clear_sg_table(struct sg_table *sgt); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) ++// Import DMA_BUF namespace for needed kernels ++MODULE_IMPORT_NS(DMA_BUF); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) */ ++ ++static int hailo_map_dmabuf(struct device *dev, int dmabuf_fd, enum dma_data_direction direction, struct sg_table *sgt, ++ struct hailo_dmabuf_info *dmabuf_info) ++{ ++ int ret = -EINVAL; ++ struct dma_buf *dmabuf = NULL; ++ struct dma_buf_attachment *dmabuf_attachment = NULL; ++ struct sg_table *res_sgt = NULL; ++ ++ dmabuf = dma_buf_get(dmabuf_fd); ++ if (IS_ERR(dmabuf)) { ++ dev_err(dev, "dma_buf_get failed, err=%ld\n", PTR_ERR(dmabuf)); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ dmabuf_attachment = dma_buf_attach(dmabuf, dev); ++ if (IS_ERR(dmabuf_attachment)) { ++ dev_err(dev, "dma_buf_attach failed, err=%ld\n", PTR_ERR(dmabuf_attachment)); ++ ret = -EINVAL; ++ goto l_buf_get; ++ } ++ ++ res_sgt = dma_buf_map_attachment(dmabuf_attachment, direction); ++ if (IS_ERR(res_sgt)) { ++ dev_err(dev, "dma_buf_map_attachment failed, err=%ld\n", PTR_ERR(res_sgt)); ++ goto l_buf_attach; ++ } ++ ++ *sgt = *res_sgt; ++ ++ dmabuf_info->dmabuf = dmabuf; ++ dmabuf_info->dmabuf_attachment = dmabuf_attachment; ++ dmabuf_info->dmabuf_sg_table = res_sgt; ++ return 0; ++ ++l_buf_attach: ++ dma_buf_detach(dmabuf, dmabuf_attachment); ++l_buf_get: ++ dma_buf_put(dmabuf); ++cleanup: ++ return ret; ++} ++ ++static void hailo_unmap_dmabuf(struct hailo_vdma_buffer *vdma_buffer) ++{ ++ dma_buf_unmap_attachment(vdma_buffer->dmabuf_info.dmabuf_attachment, vdma_buffer->dmabuf_info.dmabuf_sg_table, vdma_buffer->data_direction); ++ dma_buf_detach(vdma_buffer->dmabuf_info.dmabuf, vdma_buffer->dmabuf_info.dmabuf_attachment); ++ dma_buf_put(vdma_buffer->dmabuf_info.dmabuf); ++} ++ ++#else /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */ ++ ++static int hailo_map_dmabuf(struct device *dev, int dmabuf_fd, enum dma_data_direction direction, struct sg_table *sgt, ++ struct hailo_dmabuf_info *dmabuf_info) ++{ ++ (void) dmabuf_fd; ++ (void) direction; ++ (void) sgt; ++ (void) mapped_buffer; ++ dev_err(dev, "dmabuf not supported in kernel versions lower than 3.3.0\n"); ++ return -EINVAL; ++} ++ ++static void hailo_unmap_dmabuf(struct hailo_vdma_buffer *vdma_buffer) ++{ ++ dev_err(vdma_buffer->device, "dmabuf not supported in kernel versions lower than 3.3.0\n"); ++ return -EINVAL; ++} ++ ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */ ++ ++struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, ++ uintptr_t user_address, size_t size, enum dma_data_direction direction, ++ enum hailo_dma_buffer_type buffer_type, struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer) ++{ ++ int ret = -EINVAL; ++ struct hailo_vdma_buffer *mapped_buffer = NULL; ++ struct sg_table sgt = {0}; ++ struct vm_area_struct *vma = NULL; ++ bool is_mmio = false; ++ struct hailo_dmabuf_info dmabuf_info = {0}; ++ ++ mapped_buffer = kzalloc(sizeof(*mapped_buffer), GFP_KERNEL); ++ if (NULL == mapped_buffer) { ++ dev_err(dev, "memory alloc failed\n"); ++ ret = -ENOMEM; ++ goto cleanup; ++ } ++ ++ if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && (HAILO_DMA_DMABUF_BUFFER != buffer_type)) { ++ vma = find_vma(current->mm, user_address); ++ if (NULL == vma) { ++ dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size); ++ ret = -EFAULT; ++ goto cleanup; ++ } ++ } ++ ++ // TODO: is MMIO DMA MAPPINGS STILL needed after dmabuf ++ if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && ++ (MMIO_AND_NO_PAGES_VMA_MASK == (vma->vm_flags & MMIO_AND_NO_PAGES_VMA_MASK)) && ++ (HAILO_DMA_DMABUF_BUFFER != buffer_type)) { ++ // user_address represents memory mapped I/O and isn't backed by 'struct page' (only by pure pfn) ++ if (NULL != low_mem_driver_allocated_buffer) { ++ // low_mem_driver_allocated_buffer are backed by regular 'struct page' addresses, just in low memory ++ dev_err(dev, "low_mem_driver_allocated_buffer shouldn't be provided with an mmio address\n"); ++ ret = -EINVAL; ++ goto free_buffer_struct; ++ } ++ ++ ret = map_mmio_address(user_address, size, vma, &sgt); ++ if (ret < 0) { ++ dev_err(dev, "failed to map mmio address %d\n", ret); ++ goto free_buffer_struct; ++ } ++ ++ is_mmio = true; ++ ++ } else if (HAILO_DMA_DMABUF_BUFFER == buffer_type) { ++ // Content user_address in case of dmabuf is fd - for now ++ ret = hailo_map_dmabuf(dev, user_address, direction, &sgt, &dmabuf_info); ++ if (ret < 0) { ++ dev_err(dev, "Failed mapping dmabuf\n"); ++ goto cleanup; ++ } ++ } else { ++ // user_address is a standard 'struct page' backed memory address ++ ret = prepare_sg_table(&sgt, user_address, size, low_mem_driver_allocated_buffer); ++ if (ret < 0) { ++ dev_err(dev, "failed to set sg list for user buffer %d\n", ret); ++ goto free_buffer_struct; ++ } ++ sgt.nents = dma_map_sg(dev, sgt.sgl, sgt.orig_nents, direction); ++ if (0 == sgt.nents) { ++ dev_err(dev, "failed to map sg list for user buffer\n"); ++ ret = -ENXIO; ++ goto clear_sg_table; ++ } ++ } ++ ++ kref_init(&mapped_buffer->kref); ++ mapped_buffer->device = dev; ++ mapped_buffer->user_address = user_address; ++ mapped_buffer->size = size; ++ mapped_buffer->data_direction = direction; ++ mapped_buffer->sg_table = sgt; ++ mapped_buffer->is_mmio = is_mmio; ++ mapped_buffer->dmabuf_info = dmabuf_info; ++ ++ return mapped_buffer; ++ ++clear_sg_table: ++ clear_sg_table(&sgt); ++free_buffer_struct: ++ kfree(mapped_buffer); ++cleanup: ++ return ERR_PTR(ret); ++} ++ ++static void unmap_buffer(struct kref *kref) ++{ ++ struct hailo_vdma_buffer *buf = container_of(kref, struct hailo_vdma_buffer, kref); ++ ++ // If dmabuf - unmap and detatch dmabuf ++ if (NULL != buf->dmabuf_info.dmabuf) { ++ hailo_unmap_dmabuf(buf); ++ } else { ++ if (!buf->is_mmio) { ++ dma_unmap_sg(buf->device, buf->sg_table.sgl, buf->sg_table.orig_nents, buf->data_direction); ++ } ++ ++ clear_sg_table(&buf->sg_table); ++ } ++ kfree(buf); ++} ++ ++void hailo_vdma_buffer_get(struct hailo_vdma_buffer *buf) ++{ ++ kref_get(&buf->kref); ++} ++ ++void hailo_vdma_buffer_put(struct hailo_vdma_buffer *buf) ++{ ++ kref_put(&buf->kref, unmap_buffer); ++} ++ ++static void vdma_sync_entire_buffer(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type) ++{ ++ if (sync_type == HAILO_SYNC_FOR_CPU) { ++ dma_sync_sg_for_cpu(controller->dev, mapped_buffer->sg_table.sgl, mapped_buffer->sg_table.nents, ++ mapped_buffer->data_direction); ++ } else { ++ dma_sync_sg_for_device(controller->dev, mapped_buffer->sg_table.sgl, mapped_buffer->sg_table.nents, ++ mapped_buffer->data_direction); ++ } ++} ++ ++typedef void (*dma_sync_single_callback)(struct device *, dma_addr_t, size_t, enum dma_data_direction); ++// Map sync_info->count bytes starting at sync_info->offset ++static void vdma_sync_buffer_interval(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, ++ size_t offset, size_t size, enum hailo_vdma_buffer_sync_type sync_type) ++{ ++ size_t sync_start_offset = offset; ++ size_t sync_end_offset = offset + size; ++ dma_sync_single_callback dma_sync_single = (sync_type == HAILO_SYNC_FOR_CPU) ? ++ dma_sync_single_for_cpu : ++ dma_sync_single_for_device; ++ struct scatterlist* sg_entry = NULL; ++ size_t current_iter_offset = 0; ++ int i = 0; ++ ++ for_each_sg(mapped_buffer->sg_table.sgl, sg_entry, mapped_buffer->sg_table.nents, i) { ++ // Check if the intervals: [current_iter_offset, sg_dma_len(sg_entry)] and [sync_start_offset, sync_end_offset] ++ // have any intersection. If offset isn't at the start of a sg_entry, we still want to sync it. ++ if (max(sync_start_offset, current_iter_offset) <= min(sync_end_offset, current_iter_offset + sg_dma_len(sg_entry))) { ++ dma_sync_single(controller->dev, sg_dma_address(sg_entry), sg_dma_len(sg_entry), ++ mapped_buffer->data_direction); ++ } ++ ++ current_iter_offset += sg_dma_len(sg_entry); ++ } ++} ++ ++void hailo_vdma_buffer_sync(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type, ++ size_t offset, size_t size) ++{ ++ if ((IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && mapped_buffer->is_mmio) || ++ (NULL != mapped_buffer->dmabuf_info.dmabuf)) { ++ // MMIO buffers and dmabufs don't need to be sync'd ++ return; ++ } ++ ++ if ((offset == 0) && (size == mapped_buffer->size)) { ++ vdma_sync_entire_buffer(controller, mapped_buffer, sync_type); ++ } else { ++ vdma_sync_buffer_interval(controller, mapped_buffer, offset, size, sync_type); ++ } ++} ++ ++// Similar to vdma_buffer_sync, allow circular sync of the buffer. ++void hailo_vdma_buffer_sync_cyclic(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type, ++ size_t offset, size_t size) ++{ ++ size_t size_to_end = min(size, mapped_buffer->size - offset); ++ ++ hailo_vdma_buffer_sync(controller, mapped_buffer, sync_type, offset, size_to_end); ++ ++ if (size_to_end < size) { ++ hailo_vdma_buffer_sync(controller, mapped_buffer, sync_type, 0, size - size_to_end); ++ } ++} ++ ++struct hailo_vdma_buffer* hailo_vdma_find_mapped_user_buffer(struct hailo_vdma_file_context *context, ++ size_t buffer_handle) ++{ ++ struct hailo_vdma_buffer *cur = NULL; ++ list_for_each_entry(cur, &context->mapped_user_buffer_list, mapped_user_buffer_list) { ++ if (cur->handle == buffer_handle) { ++ return cur; ++ } ++ } ++ return NULL; ++} ++ ++void hailo_vdma_clear_mapped_user_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller) ++{ ++ struct hailo_vdma_buffer *cur = NULL, *next = NULL; ++ list_for_each_entry_safe(cur, next, &context->mapped_user_buffer_list, mapped_user_buffer_list) { ++ list_del(&cur->mapped_user_buffer_list); ++ hailo_vdma_buffer_put(cur); ++ } ++} ++ ++ ++int hailo_desc_list_create(struct device *dev, u32 descriptors_count, u16 desc_page_size, ++ uintptr_t desc_handle, bool is_circular, struct hailo_descriptors_list_buffer *descriptors) ++{ ++ size_t buffer_size = 0; ++ const u64 align = VDMA_DESCRIPTOR_LIST_ALIGN; //First addr must be aligned on 64 KB (from the VDMA registers documentation) ++ ++ buffer_size = descriptors_count * sizeof(struct hailo_vdma_descriptor); ++ buffer_size = ALIGN(buffer_size, align); ++ ++ descriptors->kernel_address = dma_alloc_coherent(dev, buffer_size, ++ &descriptors->dma_address, GFP_KERNEL | __GFP_ZERO); ++ if (descriptors->kernel_address == NULL) { ++ dev_err(dev, "Failed to allocate descriptors list, desc_count 0x%x, buffer_size 0x%zx, This failure means there is not a sufficient amount of CMA memory " ++ "(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficent memory.\n", ++ descriptors_count, buffer_size); ++ return -ENOMEM; ++ } ++ ++ descriptors->buffer_size = buffer_size; ++ descriptors->handle = desc_handle; ++ ++ descriptors->desc_list.desc_list = descriptors->kernel_address; ++ descriptors->desc_list.desc_count = descriptors_count; ++ descriptors->desc_list.desc_page_size = desc_page_size; ++ descriptors->desc_list.is_circular = is_circular; ++ ++ return 0; ++} ++ ++void hailo_desc_list_release(struct device *dev, struct hailo_descriptors_list_buffer *descriptors) ++{ ++ dma_free_coherent(dev, descriptors->buffer_size, descriptors->kernel_address, descriptors->dma_address); ++} ++ ++struct hailo_descriptors_list_buffer* hailo_vdma_find_descriptors_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t desc_handle) ++{ ++ struct hailo_descriptors_list_buffer *cur = NULL; ++ list_for_each_entry(cur, &context->descriptors_buffer_list, descriptors_buffer_list) { ++ if (cur->handle == desc_handle) { ++ return cur; ++ } ++ } ++ return NULL; ++} ++ ++void hailo_vdma_clear_descriptors_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller) ++{ ++ struct hailo_descriptors_list_buffer *cur = NULL, *next = NULL; ++ list_for_each_entry_safe(cur, next, &context->descriptors_buffer_list, descriptors_buffer_list) { ++ list_del(&cur->descriptors_buffer_list); ++ hailo_desc_list_release(controller->dev, cur); ++ kfree(cur); ++ } ++} ++ ++int hailo_vdma_low_memory_buffer_alloc(size_t size, struct hailo_vdma_low_memory_buffer *low_memory_buffer) ++{ ++ int ret = -EINVAL; ++ void *kernel_address = NULL; ++ size_t pages_count = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ size_t num_allocated = 0, i = 0; ++ void **pages = NULL; ++ ++ pages = kcalloc(pages_count, sizeof(*pages), GFP_KERNEL); ++ if (NULL == pages) { ++ pr_err("Failed to allocate pages for buffer (size %zu)\n", size); ++ ret = -ENOMEM; ++ goto cleanup; ++ } ++ ++ for (num_allocated = 0; num_allocated < pages_count; num_allocated++) { ++ // __GFP_DMA32 flag is used to limit system memory allocations to the lowest 4 GB of physical memory in order to guarantee DMA ++ // Operations will not have to use bounce buffers on certain architectures (e.g 32-bit DMA enabled architectures) ++ kernel_address = (void*)__get_free_page(__GFP_DMA32); ++ if (NULL == kernel_address) { ++ pr_err("Failed to allocate %zu coherent bytes\n", (size_t)PAGE_SIZE); ++ ret = -ENOMEM; ++ goto cleanup; ++ } ++ ++ pages[num_allocated] = kernel_address; ++ } ++ ++ low_memory_buffer->pages_count = pages_count; ++ low_memory_buffer->pages_address = pages; ++ ++ return 0; ++ ++cleanup: ++ if (NULL != pages) { ++ for (i = 0; i < num_allocated; i++) { ++ free_page((long unsigned)pages[i]); ++ } ++ ++ kfree(pages); ++ } ++ ++ return ret; ++} ++ ++void hailo_vdma_low_memory_buffer_free(struct hailo_vdma_low_memory_buffer *low_memory_buffer) ++{ ++ size_t i = 0; ++ if (NULL == low_memory_buffer) { ++ return; ++ } ++ ++ for (i = 0; i < low_memory_buffer->pages_count; i++) { ++ free_page((long unsigned)low_memory_buffer->pages_address[i]); ++ } ++ ++ kfree(low_memory_buffer->pages_address); ++} ++ ++struct hailo_vdma_low_memory_buffer* hailo_vdma_find_low_memory_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t buf_handle) ++{ ++ struct hailo_vdma_low_memory_buffer *cur = NULL; ++ list_for_each_entry(cur, &context->vdma_low_memory_buffer_list, vdma_low_memory_buffer_list) { ++ if (cur->handle == buf_handle) { ++ return cur; ++ } ++ } ++ ++ return NULL; ++} ++ ++void hailo_vdma_clear_low_memory_buffer_list(struct hailo_vdma_file_context *context) ++{ ++ struct hailo_vdma_low_memory_buffer *cur = NULL, *next = NULL; ++ list_for_each_entry_safe(cur, next, &context->vdma_low_memory_buffer_list, vdma_low_memory_buffer_list) { ++ list_del(&cur->vdma_low_memory_buffer_list); ++ hailo_vdma_low_memory_buffer_free(cur); ++ kfree(cur); ++ } ++} ++ ++int hailo_vdma_continuous_buffer_alloc(struct device *dev, size_t size, ++ struct hailo_vdma_continuous_buffer *continuous_buffer) ++{ ++ dma_addr_t dma_address = 0; ++ void *kernel_address = NULL; ++ ++ kernel_address = dma_alloc_coherent(dev, size, &dma_address, GFP_KERNEL); ++ if (NULL == kernel_address) { ++ dev_warn(dev, "Failed to allocate continuous buffer, size 0x%zx. This failure means there is not a sufficient amount of CMA memory " ++ "(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficent memory.\n", size); ++ return -ENOMEM; ++ } ++ ++ continuous_buffer->kernel_address = kernel_address; ++ continuous_buffer->dma_address = dma_address; ++ continuous_buffer->size = size; ++ return 0; ++} ++ ++void hailo_vdma_continuous_buffer_free(struct device *dev, ++ struct hailo_vdma_continuous_buffer *continuous_buffer) ++{ ++ dma_free_coherent(dev, continuous_buffer->size, continuous_buffer->kernel_address, ++ continuous_buffer->dma_address); ++} ++ ++struct hailo_vdma_continuous_buffer* hailo_vdma_find_continuous_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t buf_handle) ++{ ++ struct hailo_vdma_continuous_buffer *cur = NULL; ++ list_for_each_entry(cur, &context->continuous_buffer_list, continuous_buffer_list) { ++ if (cur->handle == buf_handle) { ++ return cur; ++ } ++ } ++ ++ return NULL; ++} ++ ++void hailo_vdma_clear_continuous_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller) ++{ ++ struct hailo_vdma_continuous_buffer *cur = NULL, *next = NULL; ++ list_for_each_entry_safe(cur, next, &context->continuous_buffer_list, continuous_buffer_list) { ++ list_del(&cur->continuous_buffer_list); ++ hailo_vdma_continuous_buffer_free(controller->dev, cur); ++ kfree(cur); ++ } ++} ++ ++// Assumes the provided user_address belongs to the vma and that MMIO_AND_NO_PAGES_VMA_MASK bits are set under ++// vma->vm_flags. This is validated in hailo_vdma_buffer_map, and won't be checked here ++#if defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, ++ struct sg_table *sgt) ++{ ++ int ret = -EINVAL; ++ unsigned long i = 0; ++ unsigned long pfn = 0; ++ unsigned long next_pfn = 0; ++ phys_addr_t phys_addr = 0; ++ dma_addr_t mmio_dma_address = 0; ++ const uintptr_t virt_addr = user_address; ++ const u32 vma_size = vma->vm_end - vma->vm_start + 1; ++ const uintptr_t num_pages = PFN_UP(virt_addr + size) - PFN_DOWN(virt_addr); ++ ++ // Check that the vma that was marked as MMIO_AND_NO_PAGES_VMA_MASK is big enough ++ if (vma_size < size) { ++ pr_err("vma (%u bytes) smaller than provided buffer (%u bytes)\n", vma_size, size); ++ return -EINVAL; ++ } ++ ++ // Get the physical address of user_address ++ ret = follow_pfn(vma, virt_addr, &pfn); ++ if (ret) { ++ pr_err("follow_pfn failed with %d\n", ret); ++ return ret; ++ } ++ phys_addr = __pfn_to_phys(pfn) + offset_in_page(virt_addr); ++ ++ // Make sure the physical memory is contiguous ++ for (i = 1; i < num_pages; ++i) { ++ ret = follow_pfn(vma, virt_addr + (i << PAGE_SHIFT), &next_pfn); ++ if (ret < 0) { ++ pr_err("follow_pfn failed with %d\n", ret); ++ return ret; ++ } ++ if (next_pfn != pfn + 1) { ++ pr_err("non-contiguous physical memory\n"); ++ return -EFAULT; ++ } ++ pfn = next_pfn; ++ } ++ ++ // phys_addr to dma ++ // TODO: need dma_map_resource here? doesn't work currently (we get dma_mapping_error on the returned dma addr) ++ // (HRT-12521) ++ mmio_dma_address = (dma_addr_t)phys_addr; ++ ++ // Create a page-less scatterlist. ++ ret = sg_alloc_table(sgt, 1, GFP_KERNEL); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ sg_assign_page(sgt->sgl, NULL); ++ sg_dma_address(sgt->sgl) = mmio_dma_address; ++ sg_dma_len(sgt->sgl) = size; ++ ++ return 0; ++} ++#else /* defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) */ ++static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, ++ struct sg_table *sgt) ++{ ++ (void) user_address; ++ (void) size; ++ (void) vma; ++ (void) sgt; ++ pr_err("MMIO DMA MAPPINGS are not supported in this kernel version\n"); ++ return -EINVAL; ++} ++#endif /* defined(HAILO_SUPPORT_MMIO_DMA_MAPPING) */ ++ ++ ++static int prepare_sg_table(struct sg_table *sg_table, uintptr_t user_address, u32 size, ++ struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer) ++{ ++ int ret = -EINVAL; ++ int pinned_pages = 0; ++ size_t npages = 0; ++ struct page **pages = NULL; ++ int i = 0; ++ struct scatterlist *sg_alloc_res = NULL; ++ ++ npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ pages = kvmalloc_array(npages, sizeof(*pages), GFP_KERNEL); ++ if (!pages) { ++ return -ENOMEM; ++ } ++ ++ // Check whether mapping user allocated buffer or driver allocated low memory buffer ++ if (NULL == low_mem_driver_allocated_buffer) { ++ mmap_read_lock(current->mm); ++ pinned_pages = get_user_pages_compact(user_address, npages, FOLL_WRITE | FOLL_FORCE, pages); ++ mmap_read_unlock(current->mm); ++ ++ if (pinned_pages < 0) { ++ pr_err("get_user_pages failed with %d\n", pinned_pages); ++ ret = pinned_pages; ++ goto exit; ++ } else if (pinned_pages != npages) { ++ pr_err("Pinned %d out of %zu\n", pinned_pages, npages); ++ ret = -EINVAL; ++ goto release_pages; ++ } ++ } else { ++ // Check to make sure in case user provides wrong buffer ++ if (npages != low_mem_driver_allocated_buffer->pages_count) { ++ pr_err("Received wrong amount of pages %zu to map expected %zu\n", ++ npages, low_mem_driver_allocated_buffer->pages_count); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ for (i = 0; i < npages; i++) { ++ pages[i] = virt_to_page(low_mem_driver_allocated_buffer->pages_address[i]); ++ get_page(pages[i]); ++ } ++ } ++ ++ sg_alloc_res = sg_alloc_table_from_pages_segment_compat(sg_table, pages, npages, ++ 0, size, SGL_MAX_SEGMENT_SIZE, NULL, 0, GFP_KERNEL); ++ if (IS_ERR(sg_alloc_res)) { ++ ret = PTR_ERR(sg_alloc_res); ++ pr_err("sg table alloc failed (err %d)..\n", ret); ++ goto release_pages; ++ } ++ ++ ret = 0; ++ goto exit; ++release_pages: ++ for (i = 0; i < pinned_pages; i++) { ++ if (!PageReserved(pages[i])) { ++ SetPageDirty(pages[i]); ++ } ++ put_page(pages[i]); ++ } ++exit: ++ kvfree(pages); ++ return ret; ++} ++ ++static void clear_sg_table(struct sg_table *sgt) ++{ ++ struct sg_page_iter iter; ++ struct page *page = NULL; ++ ++ for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) { ++ page = sg_page_iter_page(&iter); ++ if (page) { ++ if (!PageReserved(page)) { ++ SetPageDirty(page); ++ } ++ put_page(page); ++ } ++ } ++ ++ sg_free_table(sgt); ++} +diff --git a/drivers/media/pci/hailo/vdma/memory.h b/drivers/media/pci/hailo/vdma/memory.h +new file mode 100644 +index 000000000000..5819639fc899 +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/memory.h +@@ -0,0 +1,54 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++/** ++ * vDMA memory utility (including allocation and mappings) ++ */ ++ ++#ifndef _HAILO_VDMA_MEMORY_H_ ++#define _HAILO_VDMA_MEMORY_H_ ++ ++#include "vdma/vdma.h" ++ ++struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, uintptr_t user_address, size_t size, ++ enum dma_data_direction direction, enum hailo_dma_buffer_type buffer_type, ++ struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer); ++void hailo_vdma_buffer_get(struct hailo_vdma_buffer *buf); ++void hailo_vdma_buffer_put(struct hailo_vdma_buffer *buf); ++ ++void hailo_vdma_buffer_sync(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type, ++ size_t offset, size_t size); ++void hailo_vdma_buffer_sync_cyclic(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_buffer *mapped_buffer, enum hailo_vdma_buffer_sync_type sync_type, ++ size_t offset, size_t size); ++ ++struct hailo_vdma_buffer* hailo_vdma_find_mapped_user_buffer(struct hailo_vdma_file_context *context, ++ size_t buffer_handle); ++void hailo_vdma_clear_mapped_user_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller); ++ ++int hailo_desc_list_create(struct device *dev, u32 descriptors_count, u16 desc_page_size, ++ uintptr_t desc_handle, bool is_circular, struct hailo_descriptors_list_buffer *descriptors); ++void hailo_desc_list_release(struct device *dev, struct hailo_descriptors_list_buffer *descriptors); ++struct hailo_descriptors_list_buffer* hailo_vdma_find_descriptors_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t desc_handle); ++void hailo_vdma_clear_descriptors_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller); ++ ++int hailo_vdma_low_memory_buffer_alloc(size_t size, struct hailo_vdma_low_memory_buffer *low_memory_buffer); ++void hailo_vdma_low_memory_buffer_free(struct hailo_vdma_low_memory_buffer *low_memory_buffer); ++struct hailo_vdma_low_memory_buffer* hailo_vdma_find_low_memory_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t buf_handle); ++void hailo_vdma_clear_low_memory_buffer_list(struct hailo_vdma_file_context *context); ++ ++int hailo_vdma_continuous_buffer_alloc(struct device *dev, size_t size, ++ struct hailo_vdma_continuous_buffer *continuous_buffer); ++void hailo_vdma_continuous_buffer_free(struct device *dev, ++ struct hailo_vdma_continuous_buffer *continuous_buffer); ++struct hailo_vdma_continuous_buffer* hailo_vdma_find_continuous_buffer(struct hailo_vdma_file_context *context, ++ uintptr_t buf_handle); ++void hailo_vdma_clear_continuous_buffer_list(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller); ++#endif /* _HAILO_VDMA_MEMORY_H_ */ +\ No newline at end of file +diff --git a/drivers/media/pci/hailo/vdma/vdma.c b/drivers/media/pci/hailo/vdma/vdma.c +new file mode 100644 +index 000000000000..413a67f84d40 +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/vdma.c +@@ -0,0 +1,302 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++ ++#define pr_fmt(fmt) "hailo: " fmt ++ ++#include "vdma.h" ++#include "memory.h" ++#include "ioctl.h" ++#include "utils/logs.h" ++ ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) ++#include ++#else ++#include ++#endif ++ ++ ++static struct hailo_vdma_engine* init_vdma_engines(struct device *dev, ++ struct hailo_resource *channel_registers_per_engine, size_t engines_count, u32 src_channels_bitmask) ++{ ++ struct hailo_vdma_engine *engines = NULL; ++ u8 i = 0; ++ ++ engines = devm_kmalloc_array(dev, engines_count, sizeof(*engines), GFP_KERNEL); ++ if (NULL == engines) { ++ dev_err(dev, "Failed allocating vdma engines\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ for (i = 0; i < engines_count; i++) { ++ hailo_vdma_engine_init(&engines[i], i, &channel_registers_per_engine[i], src_channels_bitmask); ++ } ++ ++ return engines; ++} ++ ++static int hailo_set_dma_mask(struct device *dev) ++{ ++ int err = -EINVAL; ++ /* Check and configure DMA length */ ++ if (!(err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))) { ++ dev_notice(dev, "Probing: Enabled 64 bit dma\n"); ++ } else if (!(err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)))) { ++ dev_notice(dev, "Probing: Enabled 48 bit dma\n"); ++ } else if (!(err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)))) { ++ dev_notice(dev, "Probing: Enabled 40 bit dma\n"); ++ } else if (!(err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)))) { ++ dev_notice(dev, "Probing: Enabled 36 bit dma\n"); ++ } else if (!(err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)))) { ++ dev_notice(dev, "Probing: Enabled 32 bit dma\n"); ++ } else { ++ dev_err(dev, "Probing: Error enabling dma %d\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++int hailo_vdma_controller_init(struct hailo_vdma_controller *controller, ++ struct device *dev, struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_controller_ops *ops, ++ struct hailo_resource *channel_registers_per_engine, size_t engines_count) ++{ ++ int err = 0; ++ controller->hw = vdma_hw; ++ controller->ops = ops; ++ controller->dev = dev; ++ ++ controller->vdma_engines_count = engines_count; ++ controller->vdma_engines = init_vdma_engines(dev, channel_registers_per_engine, engines_count, ++ vdma_hw->src_channels_bitmask); ++ if (IS_ERR(controller->vdma_engines)) { ++ dev_err(dev, "Failed initialized vdma engines\n"); ++ return PTR_ERR(controller->vdma_engines); ++ } ++ ++ controller->used_by_filp = NULL; ++ spin_lock_init(&controller->interrupts_lock); ++ init_waitqueue_head(&controller->interrupts_wq); ++ ++ /* Check and configure DMA length */ ++ err = hailo_set_dma_mask(dev); ++ if (0 > err) { ++ return err; ++ } ++ ++ if (get_dma_ops(controller->dev)) { ++ hailo_dev_notice(controller->dev, "Probing: Using specialized dma_ops=%ps", get_dma_ops(controller->dev)); ++ } ++ ++ return 0; ++} ++ ++void hailo_vdma_file_context_init(struct hailo_vdma_file_context *context) ++{ ++ atomic_set(&context->last_vdma_user_buffer_handle, 0); ++ INIT_LIST_HEAD(&context->mapped_user_buffer_list); ++ ++ atomic_set(&context->last_vdma_handle, 0); ++ INIT_LIST_HEAD(&context->descriptors_buffer_list); ++ INIT_LIST_HEAD(&context->vdma_low_memory_buffer_list); ++ INIT_LIST_HEAD(&context->continuous_buffer_list); ++} ++ ++void hailo_vdma_update_interrupts_mask(struct hailo_vdma_controller *controller, ++ size_t engine_index) ++{ ++ struct hailo_vdma_engine *engine = &controller->vdma_engines[engine_index]; ++ controller->ops->update_channel_interrupts(controller, engine_index, engine->enabled_channels); ++} ++ ++void hailo_vdma_file_context_finalize(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, struct file *filp) ++{ ++ size_t engine_index = 0; ++ struct hailo_vdma_engine *engine = NULL; ++ const u32 channels_bitmap = 0xFFFFFFFF; // disable all channel interrupts ++ unsigned long irq_saved_flags = 0; ++ // In case of FLR, the vdma registers will be NULL ++ const bool is_device_up = (NULL != controller->dev); ++ ++ if (filp == controller->used_by_filp) { ++ for_each_vdma_engine(controller, engine, engine_index) { ++ hailo_vdma_engine_disable_channels(engine, channels_bitmap); ++ ++ if (is_device_up) { ++ hailo_vdma_update_interrupts_mask(controller, engine_index); ++ } ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ hailo_vdma_engine_clear_channel_interrupts(engine, channels_bitmap); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); ++ } ++ } ++ ++ hailo_vdma_clear_mapped_user_buffer_list(context, controller); ++ hailo_vdma_clear_descriptors_buffer_list(context, controller); ++ hailo_vdma_clear_low_memory_buffer_list(context); ++ hailo_vdma_clear_continuous_buffer_list(context, controller); ++ ++ if (filp == controller->used_by_filp) { ++ controller->used_by_filp = NULL; ++ } ++} ++ ++void hailo_vdma_irq_handler(struct hailo_vdma_controller *controller, ++ size_t engine_index, u32 channels_bitmap) ++{ ++ unsigned long irq_saved_flags = 0; ++ struct hailo_vdma_engine *engine = NULL; ++ ++ BUG_ON(engine_index >= controller->vdma_engines_count); ++ engine = &controller->vdma_engines[engine_index]; ++ ++ hailo_vdma_engine_push_timestamps(engine, channels_bitmap); ++ ++ spin_lock_irqsave(&controller->interrupts_lock, irq_saved_flags); ++ hailo_vdma_engine_set_channel_interrupts(engine, channels_bitmap); ++ spin_unlock_irqrestore(&controller->interrupts_lock, irq_saved_flags); ++ ++ wake_up_interruptible_all(&controller->interrupts_wq); ++} ++ ++long hailo_vdma_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned int cmd, unsigned long arg, struct file *filp, struct semaphore *mutex, bool *should_up_board_mutex) ++{ ++ switch (cmd) { ++ case HAILO_VDMA_ENABLE_CHANNELS: ++ return hailo_vdma_enable_channels_ioctl(controller, arg); ++ case HAILO_VDMA_DISABLE_CHANNELS: ++ return hailo_vdma_disable_channels_ioctl(controller, arg); ++ case HAILO_VDMA_INTERRUPTS_WAIT: ++ return hailo_vdma_interrupts_wait_ioctl(controller, arg, mutex, should_up_board_mutex); ++ case HAILO_VDMA_INTERRUPTS_READ_TIMESTAMPS: ++ return hailo_vdma_interrupts_read_timestamps_ioctl(controller, arg); ++ case HAILO_VDMA_BUFFER_MAP: ++ return hailo_vdma_buffer_map_ioctl(context, controller, arg); ++ case HAILO_VDMA_BUFFER_UNMAP: ++ return hailo_vdma_buffer_unmap_ioctl(context, controller, arg); ++ case HAILO_VDMA_BUFFER_SYNC: ++ return hailo_vdma_buffer_sync_ioctl(context, controller, arg); ++ case HAILO_DESC_LIST_CREATE: ++ return hailo_desc_list_create_ioctl(context, controller, arg); ++ case HAILO_DESC_LIST_RELEASE: ++ return hailo_desc_list_release_ioctl(context, controller, arg); ++ case HAILO_DESC_LIST_PROGRAM: ++ return hailo_desc_list_program_ioctl(context, controller, arg); ++ case HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC: ++ return hailo_vdma_low_memory_buffer_alloc_ioctl(context, controller, arg); ++ case HAILO_VDMA_LOW_MEMORY_BUFFER_FREE: ++ return hailo_vdma_low_memory_buffer_free_ioctl(context, controller, arg); ++ case HAILO_MARK_AS_IN_USE: ++ return hailo_mark_as_in_use(controller, arg, filp); ++ case HAILO_VDMA_CONTINUOUS_BUFFER_ALLOC: ++ return hailo_vdma_continuous_buffer_alloc_ioctl(context, controller, arg); ++ case HAILO_VDMA_CONTINUOUS_BUFFER_FREE: ++ return hailo_vdma_continuous_buffer_free_ioctl(context, controller, arg); ++ case HAILO_VDMA_LAUNCH_TRANSFER: ++ return hailo_vdma_launch_transfer_ioctl(context, controller, arg); ++ default: ++ hailo_dev_err(controller->dev, "Invalid vDMA ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd)); ++ return -ENOTTY; ++ } ++} ++ ++static int low_memory_buffer_mmap(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_low_memory_buffer *vdma_buffer, struct vm_area_struct *vma) ++{ ++ int err = 0; ++ size_t i = 0; ++ unsigned long vsize = vma->vm_end - vma->vm_start; ++ unsigned long orig_vm_start = vma->vm_start; ++ unsigned long orig_vm_end = vma->vm_end; ++ unsigned long page_fn = 0; ++ ++ if (vsize != vdma_buffer->pages_count * PAGE_SIZE) { ++ hailo_dev_err(controller->dev, "mmap size should be %lu (given %lu)\n", ++ vdma_buffer->pages_count * PAGE_SIZE, vsize); ++ return -EINVAL; ++ } ++ ++ for (i = 0 ; i < vdma_buffer->pages_count ; i++) { ++ if (i > 0) { ++ vma->vm_start = vma->vm_end; ++ } ++ vma->vm_end = vma->vm_start + PAGE_SIZE; ++ ++ page_fn = virt_to_phys(vdma_buffer->pages_address[i]) >> PAGE_SHIFT ; ++ err = remap_pfn_range(vma, vma->vm_start, page_fn, PAGE_SIZE, vma->vm_page_prot); ++ ++ if (err != 0) { ++ hailo_dev_err(controller->dev, " fops_mmap failed mapping kernel page %d\n", err); ++ return err; ++ } ++ } ++ ++ vma->vm_start = orig_vm_start; ++ vma->vm_end = orig_vm_end; ++ ++ return 0; ++} ++ ++static int continuous_buffer_mmap(struct hailo_vdma_controller *controller, ++ struct hailo_vdma_continuous_buffer *buffer, struct vm_area_struct *vma) ++{ ++ int err = 0; ++ const unsigned long vsize = vma->vm_end - vma->vm_start; ++ ++ if (vsize > buffer->size) { ++ hailo_dev_err(controller->dev, "mmap size should be less than %zu (given %lu)\n", ++ buffer->size, vsize); ++ return -EINVAL; ++ } ++ ++ err = dma_mmap_coherent(controller->dev, vma, buffer->kernel_address, ++ buffer->dma_address, vsize); ++ if (err < 0) { ++ hailo_dev_err(controller->dev, " vdma_mmap failed dma_mmap_coherent %d\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++int hailo_vdma_mmap(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ struct vm_area_struct *vma, uintptr_t vdma_handle) ++{ ++ struct hailo_vdma_low_memory_buffer *low_memory_buffer = NULL; ++ struct hailo_vdma_continuous_buffer *continuous_buffer = NULL; ++ ++ hailo_dev_info(controller->dev, "Map vdma_handle %llu\n", (u64)vdma_handle); ++ if (NULL != (low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, vdma_handle))) { ++ return low_memory_buffer_mmap(controller, low_memory_buffer, vma); ++ } ++ else if (NULL != (continuous_buffer = hailo_vdma_find_continuous_buffer(context, vdma_handle))) { ++ return continuous_buffer_mmap(controller, continuous_buffer, vma); ++ } ++ else { ++ hailo_dev_err(controller->dev, "Can't mmap vdma handle: %llu (not existing)\n", (u64)vdma_handle); ++ return -EINVAL; ++ } ++} ++ ++enum dma_data_direction get_dma_direction(enum hailo_dma_data_direction hailo_direction) ++{ ++ switch (hailo_direction) { ++ case HAILO_DMA_BIDIRECTIONAL: ++ return DMA_BIDIRECTIONAL; ++ case HAILO_DMA_TO_DEVICE: ++ return DMA_TO_DEVICE; ++ case HAILO_DMA_FROM_DEVICE: ++ return DMA_FROM_DEVICE; ++ default: ++ pr_err("Invalid hailo direction %d\n", hailo_direction); ++ return DMA_NONE; ++ } ++} +diff --git a/drivers/media/pci/hailo/vdma/vdma.h b/drivers/media/pci/hailo/vdma/vdma.h +new file mode 100644 +index 000000000000..c518aefc9a0c +--- /dev/null ++++ b/drivers/media/pci/hailo/vdma/vdma.h +@@ -0,0 +1,161 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/** ++ * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved. ++ **/ ++/** ++ * Hailo vdma engine definitions ++ */ ++ ++#ifndef _HAILO_VDMA_VDMA_H_ ++#define _HAILO_VDMA_VDMA_H_ ++ ++#include "hailo_ioctl_common.h" ++#include "hailo_resource.h" ++#include "vdma_common.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define VDMA_CHANNEL_CONTROL_REG_OFFSET(channel_index, direction) (((direction) == DMA_TO_DEVICE) ? \ ++ (((channel_index) << 5) + 0x0) : (((channel_index) << 5) + 0x10)) ++#define VDMA_CHANNEL_CONTROL_REG_ADDRESS(vdma_registers, channel_index, direction) \ ++ ((u8*)((vdma_registers)->address) + VDMA_CHANNEL_CONTROL_REG_OFFSET(channel_index, direction)) ++ ++#define VDMA_CHANNEL_NUM_PROC_OFFSET(channel_index, direction) (((direction) == DMA_TO_DEVICE) ? \ ++ (((channel_index) << 5) + 0x4) : (((channel_index) << 5) + 0x14)) ++#define VDMA_CHANNEL_NUM_PROC_ADDRESS(vdma_registers, channel_index, direction) \ ++ ((u8*)((vdma_registers)->address) + VDMA_CHANNEL_NUM_PROC_OFFSET(channel_index, direction)) ++ ++ ++// dmabuf is supported from linux kernel version 3.3 ++#if LINUX_VERSION_CODE < KERNEL_VERSION( 3, 3, 0 ) ++// Make dummy struct with one byte (C standards does not allow empty struct) - in order to not have to ifdef everywhere ++struct hailo_dmabuf_info { ++ uint8_t dummy; ++}; ++#else ++// dmabuf_sg_table is needed because in dma_buf_unmap_attachment() the sg_table's address has to match the ++// The one returned from dma_buf_map_attachment() - otherwise we would need to malloc each time ++struct hailo_dmabuf_info { ++ struct dma_buf *dmabuf; ++ struct dma_buf_attachment *dmabuf_attachment; ++ struct sg_table *dmabuf_sg_table; ++}; ++#endif // LINUX_VERSION_CODE < KERNEL_VERSION( 3, 3, 0 ) ++ ++struct hailo_vdma_buffer { ++ struct list_head mapped_user_buffer_list; ++ size_t handle; ++ ++ struct kref kref; ++ struct device *device; ++ ++ uintptr_t user_address; ++ u32 size; ++ enum dma_data_direction data_direction; ++ struct sg_table sg_table; ++ ++ // If this flag is set, the buffer pointed by sg_table is not backed by ++ // 'struct page' (only by pure pfn). On this case, accessing to the page, ++ // or calling APIs that access the page (e.g. dma_sync_sg_for_cpu) is not ++ // allowed. ++ bool is_mmio; ++ ++ // Relevant paramaters that need to be saved in case of dmabuf - otherwise struct pointers will be NULL ++ struct hailo_dmabuf_info dmabuf_info; ++}; ++ ++// Continuous buffer that holds a descriptor list. ++struct hailo_descriptors_list_buffer { ++ struct list_head descriptors_buffer_list; ++ uintptr_t handle; ++ void *kernel_address; ++ dma_addr_t dma_address; ++ u32 buffer_size; ++ struct hailo_vdma_descriptors_list desc_list; ++}; ++ ++struct hailo_vdma_low_memory_buffer { ++ struct list_head vdma_low_memory_buffer_list; ++ uintptr_t handle; ++ size_t pages_count; ++ void **pages_address; ++}; ++ ++struct hailo_vdma_continuous_buffer { ++ struct list_head continuous_buffer_list; ++ uintptr_t handle; ++ void *kernel_address; ++ dma_addr_t dma_address; ++ size_t size; ++}; ++ ++struct hailo_vdma_controller; ++struct hailo_vdma_controller_ops { ++ void (*update_channel_interrupts)(struct hailo_vdma_controller *controller, size_t engine_index, ++ u32 channels_bitmap); ++}; ++ ++struct hailo_vdma_controller { ++ struct hailo_vdma_hw *hw; ++ struct hailo_vdma_controller_ops *ops; ++ struct device *dev; ++ ++ size_t vdma_engines_count; ++ struct hailo_vdma_engine *vdma_engines; ++ ++ spinlock_t interrupts_lock; ++ wait_queue_head_t interrupts_wq; ++ ++ struct file *used_by_filp; ++ ++ // Putting big IOCTL structures here to avoid stack allocation. ++ struct hailo_vdma_interrupts_read_timestamp_params read_interrupt_timestamps_params; ++}; ++ ++#define for_each_vdma_engine(controller, engine, engine_index) \ ++ _for_each_element_array(controller->vdma_engines, controller->vdma_engines_count, \ ++ engine, engine_index) ++ ++struct hailo_vdma_file_context { ++ atomic_t last_vdma_user_buffer_handle; ++ struct list_head mapped_user_buffer_list; ++ ++ // Last_vdma_handle works as a handle for vdma decriptor list and for the vdma buffer - ++ // there will be no collisions between the two ++ atomic_t last_vdma_handle; ++ struct list_head descriptors_buffer_list; ++ struct list_head vdma_low_memory_buffer_list; ++ struct list_head continuous_buffer_list; ++}; ++ ++ ++int hailo_vdma_controller_init(struct hailo_vdma_controller *controller, ++ struct device *dev, struct hailo_vdma_hw *vdma_hw, ++ struct hailo_vdma_controller_ops *ops, ++ struct hailo_resource *channel_registers_per_engine, size_t engines_count); ++ ++void hailo_vdma_update_interrupts_mask(struct hailo_vdma_controller *controller, ++ size_t engine_index); ++ ++void hailo_vdma_file_context_init(struct hailo_vdma_file_context *context); ++void hailo_vdma_file_context_finalize(struct hailo_vdma_file_context *context, ++ struct hailo_vdma_controller *controller, struct file *filp); ++ ++void hailo_vdma_irq_handler(struct hailo_vdma_controller *controller, size_t engine_index, ++ u32 channels_bitmap); ++ ++// TODO: reduce params count ++long hailo_vdma_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ unsigned int cmd, unsigned long arg, struct file *filp, struct semaphore *mutex, bool *should_up_board_mutex); ++ ++int hailo_vdma_mmap(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller, ++ struct vm_area_struct *vma, uintptr_t vdma_handle); ++ ++enum dma_data_direction get_dma_direction(enum hailo_dma_data_direction hailo_direction); ++void hailo_vdma_disable_vdma_channels(struct hailo_vdma_controller *controller, const bool should_close_channels); ++ ++#endif /* _HAILO_VDMA_VDMA_H_ */ +\ No newline at end of file diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ee579916f874..8f9acc325cc8 100644 --- a/drivers/media/platform/Kconfig @@ -128263,17 +143633,17 @@ index 000000000000..4ce6c998927c +obj-y += rp1_cfe/ diff --git a/drivers/media/platform/raspberrypi/pisp_be/Kconfig b/drivers/media/platform/raspberrypi/pisp_be/Kconfig new file mode 100644 -index 000000000000..f70ccbc0a07e +index 000000000000..38c0f8305d62 --- /dev/null +++ b/drivers/media/platform/raspberrypi/pisp_be/Kconfig @@ -0,0 +1,12 @@ +config VIDEO_RASPBERRYPI_PISP_BE + tristate "Raspberry Pi PiSP Backend (BE) ISP driver" -+ depends on VIDEO_DEV && PM ++ depends on V4L_PLATFORM_DRIVERS ++ depends on VIDEO_DEV + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG -+ select V4L2_FWNODE + help + Say Y here to enable support for the PiSP Backend (BE) ISP driver. + @@ -128293,19 +143663,21 @@ index 000000000000..a70bf5716824 +obj-$(CONFIG_VIDEO_RASPBERRYPI_PISP_BE) += pisp-be.o diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c new file mode 100644 -index 000000000000..073b0e387473 +index 000000000000..f1628dcda340 --- /dev/null +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c -@@ -0,0 +1,1993 @@ +@@ -0,0 +1,1866 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PiSP Back End driver. -+ * Copyright (c) 2021-2022 Raspberry Pi Limited. ++ * Copyright (c) 2021-2024 Raspberry Pi Limited. + * + */ +#include +#include +#include ++#include ++#include +#include +#include +#include @@ -128314,13 +143686,9 @@ index 000000000000..073b0e387473 +#include +#include + -+#include "pisp_be_config.h" -+#include "pisp_be_formats.h" ++#include + -+MODULE_DESCRIPTION("PiSP Back End driver"); -+MODULE_AUTHOR("David Plowman "); -+MODULE_AUTHOR("Nick Hollinghurst "); -+MODULE_LICENSE("GPL v2"); ++#include "pisp_be_formats.h" + +/* Offset to use when registering the /dev/videoX node */ +#define PISPBE_VIDEO_NODE_OFFSET 20 @@ -128339,24 +143707,29 @@ index 000000000000..073b0e387473 +#define PISPBE_NAME "pispbe" + +/* Some ISP-BE registers */ -+#define PISP_BE_VERSION_OFFSET (0x0) -+#define PISP_BE_CONTROL_OFFSET (0x4) -+#define PISP_BE_TILE_ADDR_LO_OFFSET (0x8) -+#define PISP_BE_TILE_ADDR_HI_OFFSET (0xc) -+#define PISP_BE_STATUS_OFFSET (0x10) -+#define PISP_BE_BATCH_STATUS_OFFSET (0x14) -+#define PISP_BE_INTERRUPT_EN_OFFSET (0x18) -+#define PISP_BE_INTERRUPT_STATUS_OFFSET (0x1c) -+#define PISP_BE_AXI_OFFSET (0x20) -+#define PISP_BE_CONFIG_BASE_OFFSET (0x40) -+#define PISP_BE_IO_INPUT_ADDR0_LO_OFFSET (PISP_BE_CONFIG_BASE_OFFSET) -+#define PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x70) -+#define PISP_BE_GLOBAL_RGB_ENABLE_OFFSET (PISP_BE_CONFIG_BASE_OFFSET + 0x74) -+#define N_HW_ADDRESSES 14 -+#define N_HW_ENABLES 2 ++#define PISP_BE_VERSION_REG 0x0 ++#define PISP_BE_CONTROL_REG 0x4 ++#define PISP_BE_CONTROL_COPY_CONFIG BIT(1) ++#define PISP_BE_CONTROL_QUEUE_JOB BIT(0) ++#define PISP_BE_CONTROL_NUM_TILES(n) ((n) << 16) ++#define PISP_BE_TILE_ADDR_LO_REG 0x8 ++#define PISP_BE_TILE_ADDR_HI_REG 0xc ++#define PISP_BE_STATUS_REG 0x10 ++#define PISP_BE_STATUS_QUEUED BIT(0) ++#define PISP_BE_BATCH_STATUS_REG 0x14 ++#define PISP_BE_INTERRUPT_EN_REG 0x18 ++#define PISP_BE_INTERRUPT_STATUS_REG 0x1c ++#define PISP_BE_AXI_REG 0x20 ++#define PISP_BE_CONFIG_BASE_REG 0x40 ++#define PISP_BE_IO_ADDR_LOW(n) (PISP_BE_CONFIG_BASE_REG + 8 * (n)) ++#define PISP_BE_IO_ADDR_HIGH(n) (PISP_BE_IO_ADDR_LOW((n)) + 4) ++#define PISP_BE_GLOBAL_BAYER_ENABLE 0xb0 ++#define PISP_BE_GLOBAL_RGB_ENABLE 0xb4 ++#define N_HW_ADDRESSES 13 ++#define N_HW_ENABLES 2 + -+#define PISP_BE_VERSION_2712C1 0x02252700 -+#define PISP_BE_VERSION_MINOR_BITS 0xF ++#define PISP_BE_VERSION_2712 0x02252700 ++#define PISP_BE_VERSION_MINOR_BITS 0xf + +/* + * This maps our nodes onto the inputs/outputs of the actual PiSP Back End. @@ -128364,11 +143737,10 @@ index 000000000000..073b0e387473 + * context it means an input to the hardware (source image or metadata). + * Elsewhere it means an output from the hardware. + */ -+enum node_ids { ++enum pispbe_node_ids { + MAIN_INPUT_NODE, + TDN_INPUT_NODE, + STITCH_INPUT_NODE, -+ HOG_OUTPUT_NODE, + OUTPUT0_NODE, + OUTPUT1_NODE, + TDN_OUTPUT_NODE, @@ -128377,13 +143749,13 @@ index 000000000000..073b0e387473 + PISPBE_NUM_NODES +}; + -+struct node_description { ++struct pispbe_node_description { + const char *ent_name; + enum v4l2_buf_type buf_type; + unsigned int caps; +}; + -+static const struct node_description node_desc[PISPBE_NUM_NODES] = { ++static const struct pispbe_node_description node_desc[PISPBE_NUM_NODES] = { + /* MAIN_INPUT_NODE */ + { + .ent_name = PISPBE_NAME "-input", @@ -128402,12 +143774,6 @@ index 000000000000..073b0e387473 + .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE, + }, -+ /* HOG_OUTPUT_NODE */ -+ { -+ .ent_name = PISPBE_NAME "-hog_output", -+ .buf_type = V4L2_BUF_TYPE_META_CAPTURE, -+ .caps = V4L2_CAP_META_CAPTURE, -+ }, + /* OUTPUT0_NODE */ + { + .ent_name = PISPBE_NAME "-output0", @@ -128446,14 +143812,12 @@ index 000000000000..073b0e387473 + ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) + +#define NODE_IS_META(node) ( \ -+ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ -+ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE)) ++ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT)) +#define NODE_IS_OUTPUT(node) ( \ + ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \ + ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \ + ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) +#define NODE_IS_CAPTURE(node) ( \ -+ ((node)->buf_type == V4L2_BUF_TYPE_META_CAPTURE) || \ + ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || \ + ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) +#define NODE_IS_MPLANE(node) ( \ @@ -128473,8 +143837,11 @@ index 000000000000..073b0e387473 + struct media_intf_devnode *intf_devnode; + struct media_link *intf_link; + struct pispbe_node_group *node_group; ++ /* Video device lock */ + struct mutex node_lock; ++ /* vb2_queue lock */ + struct mutex queue_lock; ++ /* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */ + spinlock_t ready_lock; + struct list_head ready_queue; + struct vb2_queue queue; @@ -128485,7 +143852,6 @@ index 000000000000..073b0e387473 +/* For logging only, use the entity name with "pispbe" and separator removed */ +#define NODE_NAME(node) \ + (node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME)) -+#define NODE_GET_V4L2(node) ((node)->node_group->v4l2_dev) + +/* + * Node group structure, which comprises all the input and output nodes that a @@ -128515,85 +143881,57 @@ index 000000000000..073b0e387473 + struct pispbe_buffer *buf[PISPBE_NUM_NODES]; +}; + ++struct pispbe_hw_enables { ++ u32 bayer_enables; ++ u32 rgb_enables; ++}; ++ ++/* Records a job configuration and memory addresses. */ ++struct pispbe_job_descriptor { ++ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; ++ struct pisp_be_tiles_config *config; ++ struct pispbe_hw_enables hw_enables; ++ dma_addr_t tiles; ++}; ++ +/* + * Structure representing the entire PiSP Back End device, comprising several -+ * node groups which share platform resources and a mutex for the actual HW. ++ * nodes groups which share platform resources and a mutex for the actual HW. + */ +struct pispbe_dev { + struct device *dev; -+ struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS]; -+ int hw_busy; /* non-zero if a job is queued or is being started */ -+ struct pispbe_job queued_job, running_job; + void __iomem *be_reg_base; + struct clk *clk; ++ struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS]; ++ struct pispbe_job queued_job, running_job; ++ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */ ++ bool hw_busy; /* non-zero if a job is queued or is being started */ + int irq; + u32 hw_version; + u8 done, started; -+ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */ +}; + -+static inline u32 read_reg(struct pispbe_dev *pispbe, unsigned int offset) ++static u32 pispbe_rd(struct pispbe_dev *pispbe, unsigned int offset) +{ + return readl(pispbe->be_reg_base + offset); +} + -+static inline void write_reg(struct pispbe_dev *pispbe, unsigned int offset, -+ u32 val) ++static void pispbe_wr(struct pispbe_dev *pispbe, unsigned int offset, u32 val) +{ + writel(val, pispbe->be_reg_base + offset); +} + -+/* Check and initialize hardware. */ -+static int hw_init(struct pispbe_dev *pispbe) -+{ -+ u32 u; -+ -+ /* Check the HW is present and has a known version */ -+ u = read_reg(pispbe, PISP_BE_VERSION_OFFSET); -+ dev_info(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u); -+ pispbe->hw_version = u; -+ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712C1) -+ return -ENODEV; -+ -+ /* Clear leftover interrupts */ -+ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, 0xFFFFFFFFu); -+ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); -+ dev_info(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u); -+ pispbe->done = (uint8_t)u; -+ pispbe->started = (uint8_t)(u >> 8); -+ u = read_reg(pispbe, PISP_BE_STATUS_OFFSET); -+ dev_info(pispbe->dev, "pispbe_probe: Status: 0x%08x", u); -+ if (u != 0 || pispbe->done != pispbe->started) { -+ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n"); -+ return -EBUSY; -+ } -+ /* -+ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011 -+ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts -+ * and AXI AWID/BID variability (on versions which support this). -+ */ -+ write_reg(pispbe, PISP_BE_AXI_OFFSET, 0x32703200u); -+ -+ /* Enable both interrupt flags */ -+ write_reg(pispbe, PISP_BE_INTERRUPT_EN_OFFSET, 0x00000003u); -+ return 0; -+} -+ +/* + * Queue a job to the h/w. If the h/w is idle it will begin immediately. + * Caller must ensure it is "safe to queue", i.e. we don't already have a + * queued, unstarted job. + */ -+static void hw_queue_job(struct pispbe_dev *pispbe, -+ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES], -+ u32 hw_enables[N_HW_ENABLES], -+ struct pisp_be_config *config, dma_addr_t tiles, -+ unsigned int num_tiles) ++static void pispbe_queue_job(struct pispbe_dev *pispbe, ++ struct pispbe_job_descriptor *job) +{ + unsigned int begin, end; -+ unsigned int u; + -+ if (read_reg(pispbe, PISP_BE_STATUS_OFFSET) & 1) ++ if (pispbe_rd(pispbe, PISP_BE_STATUS_REG) & PISP_BE_STATUS_QUEUED) + dev_err(pispbe->dev, "ERROR: not safe to queue new job!\n"); + + /* @@ -128602,51 +143940,49 @@ index 000000000000..073b0e387473 + * and we don't want to modify (or be vulnerable to modifications of) + * the mmap'd buffer. + */ -+ for (u = 0; u < N_HW_ADDRESSES; ++u) { -+ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u, -+ (u32)(hw_dma_addrs[u])); -+ write_reg(pispbe, PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u + 4, -+ (u32)(hw_dma_addrs[u] >> 32)); ++ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) { ++ pispbe_wr(pispbe, PISP_BE_IO_ADDR_LOW(u), ++ lower_32_bits(job->hw_dma_addrs[u])); ++ pispbe_wr(pispbe, PISP_BE_IO_ADDR_HIGH(u), ++ upper_32_bits(job->hw_dma_addrs[u])); + } -+ write_reg(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE_OFFSET, hw_enables[0]); -+ write_reg(pispbe, PISP_BE_GLOBAL_RGB_ENABLE_OFFSET, hw_enables[1]); ++ pispbe_wr(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE, ++ job->hw_enables.bayer_enables); ++ pispbe_wr(pispbe, PISP_BE_GLOBAL_RGB_ENABLE, ++ job->hw_enables.rgb_enables); + -+ /* -+ * Everything else is as supplied by the user. XXX Buffer sizes not -+ * checked! -+ */ ++ /* Everything else is as supplied by the user. */ + begin = offsetof(struct pisp_be_config, global.bayer_order) / -+ sizeof(u32); -+ end = offsetof(struct pisp_be_config, axi) / sizeof(u32); -+ for (u = begin; u < end; u++) { -+ unsigned int val = ((u32 *)config)[u]; -+ -+ write_reg(pispbe, PISP_BE_CONFIG_BASE_OFFSET + 4 * u, val); -+ } ++ sizeof(u32); ++ end = sizeof(struct pisp_be_config) / sizeof(u32); ++ for (unsigned int u = begin; u < end; u++) ++ pispbe_wr(pispbe, PISP_BE_CONFIG_BASE_REG + sizeof(u32) * u, ++ ((u32 *)job->config)[u]); + + /* Read back the addresses -- an error here could be fatal */ -+ for (u = 0; u < N_HW_ADDRESSES; ++u) { -+ unsigned int offset = PISP_BE_IO_INPUT_ADDR0_LO_OFFSET + 8 * u; -+ u64 along = read_reg(pispbe, offset); ++ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) { ++ unsigned int offset = PISP_BE_IO_ADDR_LOW(u); ++ u64 along = pispbe_rd(pispbe, offset); + -+ along += ((u64)read_reg(pispbe, offset + 4)) << 32; -+ if (along != (u64)(hw_dma_addrs[u])) { -+ dev_err(pispbe->dev, ++ along += ((u64)pispbe_rd(pispbe, offset + 4)) << 32; ++ if (along != (u64)(job->hw_dma_addrs[u])) { ++ dev_dbg(pispbe->dev, + "ISP BE config error: check if ISP RAMs enabled?\n"); + return; + } + } + + /* -+ * Write tile pointer to hardware. XXX Tile offsets and sizes not -+ * checked (and even if checked, the user could subsequently modify -+ * them)! ++ * Write tile pointer to hardware. The IOMMU should prevent ++ * out-of-bounds offsets reaching non-ISP buffers. + */ -+ write_reg(pispbe, PISP_BE_TILE_ADDR_LO_OFFSET, (u32)tiles); -+ write_reg(pispbe, PISP_BE_TILE_ADDR_HI_OFFSET, (u32)(tiles >> 32)); ++ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_LO_REG, lower_32_bits(job->tiles)); ++ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_HI_REG, upper_32_bits(job->tiles)); + + /* Enqueue the job */ -+ write_reg(pispbe, PISP_BE_CONTROL_OFFSET, 3 + 65536 * num_tiles); ++ pispbe_wr(pispbe, PISP_BE_CONTROL_REG, ++ PISP_BE_CONTROL_COPY_CONFIG | PISP_BE_CONTROL_QUEUE_JOB | ++ PISP_BE_CONTROL_NUM_TILES(job->config->num_tiles)); +} + +struct pispbe_buffer { @@ -128655,8 +143991,8 @@ index 000000000000..073b0e387473 + unsigned int config_index; +}; + -+static int get_addr_3(dma_addr_t addr[3], struct pispbe_buffer *buf, -+ struct pispbe_node *node) ++static int pispbe_get_planes_addr(dma_addr_t addr[3], struct pispbe_buffer *buf, ++ struct pispbe_node *node) +{ + unsigned int num_planes = node->format.fmt.pix_mp.num_planes; + unsigned int plane_factor = 0; @@ -128666,22 +144002,20 @@ index 000000000000..073b0e387473 + if (!buf || !node->pisp_format) + return 0; + -+ WARN_ON(!NODE_IS_MPLANE(node)); -+ + /* + * Determine the base plane size. This will not be the same + * as node->format.fmt.pix_mp.plane_fmt[0].sizeimage for a single + * plane buffer in an mplane format. + */ + size = node->format.fmt.pix_mp.plane_fmt[0].bytesperline * -+ node->format.fmt.pix_mp.height; ++ node->format.fmt.pix_mp.height; + -+ for (p = 0; p < num_planes && p < 3; p++) { ++ for (p = 0; p < num_planes && p < PISPBE_MAX_PLANES; p++) { + addr[p] = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, p); + plane_factor += node->pisp_format->plane_factor[p]; + } + -+ for (; p < MAX_PLANES && node->pisp_format->plane_factor[p]; p++) { ++ for (; p < PISPBE_MAX_PLANES && node->pisp_format->plane_factor[p]; p++) { + /* + * Calculate the address offset of this plane as needed + * by the hardware. This is specifically for non-mplane @@ -128695,41 +144029,41 @@ index 000000000000..073b0e387473 + return num_planes; +} + -+static dma_addr_t get_addr(struct pispbe_buffer *buf) ++static dma_addr_t pispbe_get_addr(struct pispbe_buffer *buf) +{ + if (buf) + return vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ + return 0; +} + -+static void -+fixup_addrs_enables(dma_addr_t addrs[N_HW_ADDRESSES], -+ u32 hw_enables[N_HW_ENABLES], -+ struct pisp_be_tiles_config *config, -+ struct pispbe_buffer *buf[PISPBE_NUM_NODES], -+ struct pispbe_node_group *node_group) ++static void pispbe_xlate_addrs(struct pispbe_job_descriptor *job, ++ struct pispbe_buffer *buf[PISPBE_NUM_NODES], ++ struct pispbe_node_group *node_group) +{ -+ int ret, i; ++ struct pispbe_hw_enables *hw_en = &job->hw_enables; ++ struct pisp_be_tiles_config *config = job->config; ++ dma_addr_t *addrs = job->hw_dma_addrs; ++ int ret; + + /* Take a copy of the "enable" bitmaps so we can modify them. */ -+ hw_enables[0] = config->config.global.bayer_enables; -+ hw_enables[1] = config->config.global.rgb_enables; ++ hw_en->bayer_enables = config->config.global.bayer_enables; ++ hw_en->rgb_enables = config->config.global.rgb_enables; + + /* + * Main input first. There are 3 address pointers, corresponding to up + * to 3 planes. + */ -+ ret = get_addr_3(addrs, buf[MAIN_INPUT_NODE], -+ &node_group->node[MAIN_INPUT_NODE]); ++ ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE], ++ &node_group->node[MAIN_INPUT_NODE]); + if (ret <= 0) { + /* + * This shouldn't happen; pispbe_schedule_internal should insist + * on an input. + */ -+ dev_warn(node_group->pispbe->dev, -+ "ISP-BE missing input\n"); -+ hw_enables[0] = 0; -+ hw_enables[1] = 0; ++ dev_warn(node_group->pispbe->dev, "ISP-BE missing input\n"); ++ hw_en->bayer_enables = 0; ++ hw_en->rgb_enables = 0; + return; + } + @@ -128738,118 +144072,115 @@ index 000000000000..073b0e387473 + * used with Bayer input. Input enables must match the requirements + * of the processing stages, otherwise the hardware can lock up! + */ -+ if (hw_enables[0] & PISP_BE_BAYER_ENABLE_INPUT) { -+ addrs[3] = get_addr(buf[TDN_INPUT_NODE]); ++ if (hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) { ++ addrs[3] = pispbe_get_addr(buf[TDN_INPUT_NODE]); + if (addrs[3] == 0 || -+ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN_INPUT) || -+ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_TDN) || ++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN_INPUT) || ++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN) || + (config->config.tdn.reset & 1)) { -+ hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_INPUT | -+ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS); ++ hw_en->bayer_enables &= ++ ~(PISP_BE_BAYER_ENABLE_TDN_INPUT | ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS); + if (!(config->config.tdn.reset & 1)) -+ hw_enables[0] &= ~PISP_BE_BAYER_ENABLE_TDN; ++ hw_en->bayer_enables &= ++ ~PISP_BE_BAYER_ENABLE_TDN; + } + -+ addrs[4] = get_addr(buf[STITCH_INPUT_NODE]); ++ addrs[4] = pispbe_get_addr(buf[STITCH_INPUT_NODE]); + if (addrs[4] == 0 || -+ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH_INPUT) || -+ !(hw_enables[0] & PISP_BE_BAYER_ENABLE_STITCH)) { -+ hw_enables[0] &= ++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_INPUT) || ++ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH)) { ++ hw_en->bayer_enables &= + ~(PISP_BE_BAYER_ENABLE_STITCH_INPUT | + PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS | + PISP_BE_BAYER_ENABLE_STITCH); + } + -+ addrs[5] = get_addr(buf[TDN_OUTPUT_NODE]); ++ addrs[5] = pispbe_get_addr(buf[TDN_OUTPUT_NODE]); + if (addrs[5] == 0) -+ hw_enables[0] &= ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS | -+ PISP_BE_BAYER_ENABLE_TDN_OUTPUT); ++ hw_en->bayer_enables &= ++ ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS | ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT); + -+ addrs[6] = get_addr(buf[STITCH_OUTPUT_NODE]); ++ addrs[6] = pispbe_get_addr(buf[STITCH_OUTPUT_NODE]); + if (addrs[6] == 0) -+ hw_enables[0] &= ++ hw_en->bayer_enables &= + ~(PISP_BE_BAYER_ENABLE_STITCH_COMPRESS | + PISP_BE_BAYER_ENABLE_STITCH_OUTPUT); + } else { + /* No Bayer input? Disable entire Bayer pipe (else lockup) */ -+ hw_enables[0] = 0; ++ hw_en->bayer_enables = 0; + } + + /* Main image output channels. */ -+ for (i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) { -+ ret = get_addr_3(addrs + 7 + 3 * i, buf[OUTPUT0_NODE + i], -+ &node_group->node[OUTPUT0_NODE + i]); ++ for (unsigned int i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) { ++ ret = pispbe_get_planes_addr(addrs + 7 + 3 * i, ++ buf[OUTPUT0_NODE + i], ++ &node_group->node[OUTPUT0_NODE + i]); + if (ret <= 0) -+ hw_enables[1] &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i); ++ hw_en->rgb_enables &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i); + } -+ -+ /* HoG output (always single plane). */ -+ addrs[13] = get_addr(buf[HOG_OUTPUT_NODE]); -+ if (addrs[13] == 0) -+ hw_enables[1] &= ~PISP_BE_RGB_ENABLE_HOG; +} + +/* -+ * Internal function. Called from pispbe_schedule_one/all. Returns non-zero if -+ * we started a job. ++ * Prepare a job description to be submitted to the HW. + * -+ * Warning: needs to be called with hw_lock taken, and releases it if it -+ * schedules a job. ++ * To schedule a job, we need all streaming nodes (apart from Output0, ++ * Output1, Tdn and Stitch) to have a buffer ready, which must ++ * include at least a config buffer and a main input image. ++ * ++ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be ++ * available if the blocks are enabled in the config. ++ * ++ * Needs to be called with hw_lock held. ++ * ++ * Returns 0 if a job has been successfully prepared, < 0 otherwise. + */ -+static int pispbe_schedule_internal(struct pispbe_node_group *node_group, -+ unsigned long flags) ++static int pispbe_prepare_job(struct pispbe_node_group *node_group, ++ struct pispbe_job_descriptor *job) +{ -+ struct pisp_be_tiles_config *config_tiles_buffer; ++ struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {}; + struct pispbe_dev *pispbe = node_group->pispbe; -+ struct pispbe_buffer *buf[PISPBE_NUM_NODES]; -+ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; -+ dma_addr_t tiles; -+ u32 hw_enables[N_HW_ENABLES]; -+ struct pispbe_node *node; -+ unsigned long flags1; + unsigned int config_index; -+ int i; ++ struct pispbe_node *node; ++ unsigned long flags; ++ ++ lockdep_assert_held(&pispbe->hw_lock); ++ ++ memset(job, 0, sizeof(struct pispbe_job_descriptor)); + -+ /* -+ * To schedule a job, we need all streaming nodes (apart from Output0, -+ * Output1, Tdn and Stitch) to have a buffer ready, which must -+ * include at least a config buffer and a main input image. -+ * -+ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be -+ * available if the blocks are enabled in the config. -+ * -+ * (Note that streaming_map is protected by hw_lock, which is held.) -+ */ + if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) & + node_group->streaming_map) != -+ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) { -+ dev_dbg(pispbe->dev, "Nothing to do\n"); -+ return 0; -+ } ++ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) ++ return -ENODEV; + + node = &node_group->node[CONFIG_NODE]; -+ spin_lock_irqsave(&node->ready_lock, flags1); -+ buf[CONFIG_NODE] = -+ list_first_entry_or_null(&node->ready_queue, struct pispbe_buffer, -+ ready_list); -+ spin_unlock_irqrestore(&node->ready_lock, flags1); ++ spin_lock_irqsave(&node->ready_lock, flags); ++ buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue, ++ struct pispbe_buffer, ++ ready_list); ++ if (buf[CONFIG_NODE]) { ++ list_del(&buf[CONFIG_NODE]->ready_list); ++ pispbe->queued_job.buf[CONFIG_NODE] = buf[CONFIG_NODE]; ++ } ++ spin_unlock_irqrestore(&node->ready_lock, flags); + + /* Exit early if no config buffer has been queued. */ + if (!buf[CONFIG_NODE]) -+ return 0; ++ return -ENODEV; + + config_index = buf[CONFIG_NODE]->vb.vb2_buf.index; -+ config_tiles_buffer = &node_group->config[config_index]; -+ tiles = (dma_addr_t)node_group->config_dma_addr + -+ config_index * sizeof(struct pisp_be_tiles_config) + -+ offsetof(struct pisp_be_tiles_config, tiles); ++ job->config = &node_group->config[config_index]; ++ job->tiles = node_group->config_dma_addr + ++ config_index * sizeof(struct pisp_be_tiles_config) + ++ offsetof(struct pisp_be_tiles_config, tiles); + + /* remember: srcimages, captures then metadata */ -+ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) { + unsigned int bayer_en = -+ config_tiles_buffer->config.global.bayer_enables; ++ job->config->config.global.bayer_enables; + unsigned int rgb_en = -+ config_tiles_buffer->config.global.rgb_enables; ++ job->config->config.global.rgb_enables; + bool ignore_buffers = false; + + /* Config node is handled outside the loop above. */ @@ -128877,119 +144208,117 @@ index 000000000000..073b0e387473 + * global enables aren't set for these blocks. If a + * buffer has been provided, we dequeue it back to the + * user with the other in-use buffers. -+ * + */ + ignore_buffers = true; + } + + node = &node_group->node[i]; + -+ spin_lock_irqsave(&node->ready_lock, flags1); ++ /* Pull a buffer from each V4L2 queue to form the queued job */ ++ spin_lock_irqsave(&node->ready_lock, flags); + buf[i] = list_first_entry_or_null(&node->ready_queue, + struct pispbe_buffer, + ready_list); -+ spin_unlock_irqrestore(&node->ready_lock, flags1); -+ if (!buf[i] && !ignore_buffers) { -+ dev_dbg(pispbe->dev, "Nothing to do\n"); -+ return 0; -+ } -+ } -+ -+ /* Pull a buffer from each V4L2 queue to form the queued job */ -+ for (i = 0; i < PISPBE_NUM_NODES; i++) { + if (buf[i]) { -+ node = &node_group->node[i]; -+ -+ spin_lock_irqsave(&node->ready_lock, flags1); + list_del(&buf[i]->ready_list); -+ spin_unlock_irqrestore(&node->ready_lock, -+ flags1); ++ pispbe->queued_job.buf[i] = buf[i]; + } -+ pispbe->queued_job.buf[i] = buf[i]; ++ spin_unlock_irqrestore(&node->ready_lock, flags); ++ ++ if (!buf[i] && !ignore_buffers) ++ goto err_return_buffers; + } + + pispbe->queued_job.node_group = node_group; -+ pispbe->hw_busy = 1; -+ spin_unlock_irqrestore(&pispbe->hw_lock, flags); -+ -+ /* -+ * We can kick the job off without the hw_lock, as this can -+ * never run again until hw_busy is cleared, which will happen -+ * only when the following job has been queued. -+ */ -+ dev_dbg(pispbe->dev, "Have buffers - starting hardware\n"); + + /* Convert buffers to DMA addresses for the hardware */ -+ fixup_addrs_enables(hw_dma_addrs, hw_enables, -+ config_tiles_buffer, buf, node_group); -+ /* -+ * This could be a spot to fill in the -+ * buf[i]->vb.vb2_buf.planes[j].bytesused fields? -+ */ -+ i = config_tiles_buffer->num_tiles; -+ if (i <= 0 || i > PISP_BACK_END_NUM_TILES || -+ !((hw_enables[0] | hw_enables[1]) & -+ PISP_BE_BAYER_ENABLE_INPUT)) { -+ /* -+ * Bad job. We can't let it proceed as it could lock up -+ * the hardware, or worse! -+ * -+ * XXX How to deal with this most cleanly? For now, just -+ * force num_tiles to 0, which causes the H/W to do -+ * something bizarre but survivable. It increments -+ * (started,done) counters by more than 1, but we seem -+ * to survive... -+ */ -+ dev_err(pispbe->dev, "PROBLEM: Bad job"); -+ i = 0; -+ } -+ hw_queue_job(pispbe, hw_dma_addrs, hw_enables, -+ &config_tiles_buffer->config, tiles, i); ++ pispbe_xlate_addrs(job, buf, node_group); + -+ return 1; -+} ++ return 0; + -+/* Try and schedule a job for just a single node group. */ -+static void pispbe_schedule_one(struct pispbe_node_group *node_group) -+{ -+ struct pispbe_dev *pispbe = node_group->pispbe; -+ unsigned long flags; -+ int ret; ++err_return_buffers: ++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) { ++ struct pispbe_node *n = &node_group->node[i]; + -+ spin_lock_irqsave(&pispbe->hw_lock, flags); -+ if (pispbe->hw_busy) { -+ spin_unlock_irqrestore(&pispbe->hw_lock, flags); -+ return; ++ if (!buf[i]) ++ continue; ++ ++ /* Return the buffer to the ready_list queue */ ++ spin_lock_irqsave(&n->ready_lock, flags); ++ list_add(&buf[i]->ready_list, &n->ready_queue); ++ spin_unlock_irqrestore(&n->ready_lock, flags); + } + -+ /* A non-zero return means the lock was released. */ -+ ret = pispbe_schedule_internal(node_group, flags); -+ if (!ret) -+ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job)); ++ ++ return -ENODEV; +} + -+/* Try and schedule a job for any of the node groups. */ -+static void pispbe_schedule_any(struct pispbe_dev *pispbe, int clear_hw_busy) ++static void pispbe_schedule(struct pispbe_dev *pispbe, ++ struct pispbe_node_group *node_group, ++ bool clear_hw_busy) +{ ++ struct pispbe_job_descriptor job; + unsigned long flags; + + spin_lock_irqsave(&pispbe->hw_lock, flags); + + if (clear_hw_busy) -+ pispbe->hw_busy = 0; -+ if (pispbe->hw_busy == 0) { -+ unsigned int i; ++ pispbe->hw_busy = false; + -+ for (i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) { ++ if (pispbe->hw_busy) ++ goto unlock_and_return; ++ ++ for (unsigned int i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) { ++ int ret; ++ ++ /* Schedule jobs only for a specific group. */ ++ if (node_group && &pispbe->node_group[i] != node_group) ++ continue; ++ ++ /* ++ * Prepare a job for this group, if the group is not ready ++ * continue and try with the next one. ++ */ ++ ret = pispbe_prepare_job(&pispbe->node_group[i], &job); ++ if (ret) ++ continue; ++ ++ /* ++ * We can kick the job off without the hw_lock, as this can ++ * never run again until hw_busy is cleared, which will happen ++ * only when the following job has been queued and an interrupt ++ * is rised. ++ */ ++ pispbe->hw_busy = true; ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ if (job.config->num_tiles <= 0 || ++ job.config->num_tiles > PISP_BACK_END_NUM_TILES || ++ !((job.hw_enables.bayer_enables | ++ job.hw_enables.rgb_enables) & ++ PISP_BE_BAYER_ENABLE_INPUT)) { + /* -+ * A non-zero return from pispbe_schedule_internal means -+ * the lock was released. ++ * Bad job. We can't let it proceed as it could lock up ++ * the hardware, or worse! ++ * ++ * For now, just force num_tiles to 0, which causes the ++ * H/W to do something bizarre but survivable. It ++ * increments (started,done) counters by more than 1, ++ * but we seem to survive... + */ -+ if (pispbe_schedule_internal(&pispbe->node_group[i], -+ flags)) -+ return; ++ dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n", ++ job.config->num_tiles); ++ job.config->num_tiles = 0; + } ++ ++ pispbe_queue_job(pispbe, &job); ++ ++ return; + } ++ ++unlock_and_return: ++ /* No job has been queued, just release the lock and return. */ + spin_unlock_irqrestore(&pispbe->hw_lock, flags); +} + @@ -128998,9 +144327,8 @@ index 000000000000..073b0e387473 +{ + struct pispbe_buffer **buf = job->buf; + u64 ts = ktime_get_ns(); -+ int i; + -+ for (i = 0; i < PISPBE_NUM_NODES; i++) { ++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) { + if (buf[i]) { + buf[i]->vb.vb2_buf.timestamp = ts; + buf[i]->vb.sequence = job->node_group->sequence; @@ -129015,23 +144343,18 @@ index 000000000000..073b0e387473 +static irqreturn_t pispbe_isr(int irq, void *dev) +{ + struct pispbe_dev *pispbe = (struct pispbe_dev *)dev; ++ bool can_queue_another = false; + u8 started, done; -+ int can_queue_another = 0; + u32 u; + -+ u = read_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET); ++ u = pispbe_rd(pispbe, PISP_BE_INTERRUPT_STATUS_REG); + if (u == 0) + return IRQ_NONE; + -+ write_reg(pispbe, PISP_BE_INTERRUPT_STATUS_OFFSET, u); -+ dev_dbg(pispbe->dev, "Hardware interrupt\n"); -+ u = read_reg(pispbe, PISP_BE_BATCH_STATUS_OFFSET); ++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, u); ++ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG); + done = (uint8_t)u; + started = (uint8_t)(u >> 8); -+ dev_dbg(pispbe->dev, -+ "H/W started %d done %d, previously started %d done %d\n", -+ (int)started, (int)done, (int)pispbe->started, -+ (int)pispbe->done); + + /* + * Be aware that done can go up by 2 and started by 1 when: a job that @@ -129042,18 +144365,15 @@ index 000000000000..073b0e387473 + pispbe_isr_jobdone(pispbe, &pispbe->running_job); + memset(&pispbe->running_job, 0, sizeof(pispbe->running_job)); + pispbe->done++; -+ dev_dbg(pispbe->dev, "Job done (1)\n"); + } + + if (pispbe->started != started) { + pispbe->started++; + can_queue_another = 1; -+ dev_dbg(pispbe->dev, "Job started\n"); + + if (pispbe->done != done && pispbe->queued_job.node_group) { + pispbe_isr_jobdone(pispbe, &pispbe->queued_job); + pispbe->done++; -+ dev_dbg(pispbe->dev, "Job done (2)\n"); + } else { + pispbe->running_job = pispbe->queued_job; + } @@ -129062,13 +144382,15 @@ index 000000000000..073b0e387473 + } + + if (pispbe->done != done || pispbe->started != started) { -+ dev_err(pispbe->dev, "PROBLEM: counters not matching!\n"); ++ dev_dbg(pispbe->dev, ++ "Job counters not matching: done = %u, expected %u - started = %u, expected %u\n", ++ pispbe->done, done, pispbe->started, started); + pispbe->started = started; + pispbe->done = done; + } + + /* check if there's more to do before going to sleep */ -+ pispbe_schedule_any(pispbe, can_queue_another); ++ pispbe_schedule(pispbe, NULL, can_queue_another); + + return IRQ_HANDLED; +} @@ -129080,11 +144402,11 @@ index 000000000000..073b0e387473 + u32 rgb_enables = config->config.global.rgb_enables; + struct device *dev = node_group->pispbe->dev; + struct v4l2_format *fmt; -+ unsigned int bpl, size, i, j; ++ unsigned int bpl, size; + + if (!(bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) == + !(rgb_enables & PISP_BE_RGB_ENABLE_INPUT)) { -+ dev_err(dev, "%s: Not one input enabled\n", __func__); ++ dev_dbg(dev, "%s: Not one input enabled\n", __func__); + return -EIO; + } + @@ -129093,13 +144415,15 @@ index 000000000000..073b0e387473 + if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) { + bpl = config->config.tdn_output_format.stride; + size = bpl * config->config.tdn_output_format.height; ++ + if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) { -+ dev_err(dev, "%s: bpl mismatch on tdn_output\n", ++ dev_dbg(dev, "%s: bpl mismatch on tdn_output\n", + __func__); + return -EINVAL; + } ++ + if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) { -+ dev_err(dev, "%s: size mismatch on tdn_output\n", ++ dev_dbg(dev, "%s: size mismatch on tdn_output\n", + __func__); + return -EINVAL; + } @@ -129109,27 +144433,30 @@ index 000000000000..073b0e387473 + if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) { + bpl = config->config.stitch_output_format.stride; + size = bpl * config->config.stitch_output_format.height; ++ + if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) { -+ dev_err(dev, "%s: bpl mismatch on stitch_output\n", ++ dev_dbg(dev, "%s: bpl mismatch on stitch_output\n", + __func__); + return -EINVAL; + } ++ + if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) { -+ dev_err(dev, "%s: size mismatch on stitch_output\n", ++ dev_dbg(dev, "%s: size mismatch on stitch_output\n", + __func__); + return -EINVAL; + } + } + -+ for (j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) { ++ for (unsigned int j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) { + if (!(rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT(j))) + continue; ++ + if (config->config.output_format[j].image.format & + PISP_IMAGE_FORMAT_WALLPAPER_ROLL) + continue; /* TODO: Size checks for wallpaper formats */ + + fmt = &node_group->node[OUTPUT0_NODE + j].format; -+ for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) { ++ for (unsigned int i = 0; i < fmt->fmt.pix_mp.num_planes; i++) { + bpl = !i ? config->config.output_format[j].image.stride + : config->config.output_format[j].image.stride2; + size = bpl * config->config.output_format[j].image.height; @@ -129137,13 +144464,15 @@ index 000000000000..073b0e387473 + if (config->config.output_format[j].image.format & + PISP_IMAGE_FORMAT_SAMPLING_420) + size >>= 1; ++ + if (fmt->fmt.pix_mp.plane_fmt[i].bytesperline < bpl) { -+ dev_err(dev, "%s: bpl mismatch on output %d\n", ++ dev_dbg(dev, "%s: bpl mismatch on output %d\n", + __func__, j); + return -EINVAL; + } ++ + if (fmt->fmt.pix_mp.plane_fmt[i].sizeimage < size) { -+ dev_err(dev, "%s: size mismatch on output\n", ++ dev_dbg(dev, "%s: size mismatch on output\n", + __func__); + return -EINVAL; + } @@ -129159,31 +144488,31 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = vb2_get_drv_priv(q); + struct pispbe_dev *pispbe = node->node_group->pispbe; ++ unsigned int num_planes = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.num_planes : 1; + -+ *nplanes = 1; -+ if (NODE_IS_MPLANE(node)) { -+ unsigned int i; ++ if (*nplanes) { ++ if (*nplanes != num_planes) ++ return -EINVAL; + -+ *nplanes = node->format.fmt.pix_mp.num_planes; -+ for (i = 0; i < *nplanes; i++) { -+ unsigned int size = -+ node->format.fmt.pix_mp.plane_fmt[i].sizeimage; -+ if (sizes[i] && sizes[i] < size) { -+ dev_err(pispbe->dev, "%s: size %u < %u\n", -+ __func__, sizes[i], size); ++ for (unsigned int i = 0; i < *nplanes; i++) { ++ unsigned int size = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage : ++ node->format.fmt.meta.buffersize; ++ ++ if (sizes[i] < size) + return -EINVAL; -+ } -+ sizes[i] = size; + } -+ } else if (NODE_IS_META(node)) { -+ sizes[0] = node->format.fmt.meta.buffersize; -+ /* -+ * Limit the config node buffer count to the number of internal -+ * buffers allocated. -+ */ -+ if (node->id == CONFIG_NODE) -+ *nbuffers = min_t(unsigned int, *nbuffers, -+ PISP_BE_NUM_CONFIG_BUFFERS); ++ ++ return 0; ++ } ++ ++ *nplanes = num_planes; ++ for (unsigned int i = 0; i < *nplanes; i++) { ++ unsigned int size = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage : ++ node->format.fmt.meta.buffersize; ++ sizes[i] = size; + } + + dev_dbg(pispbe->dev, @@ -129197,18 +144526,16 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ unsigned long size = 0; + unsigned int num_planes = NODE_IS_MPLANE(node) ? -+ node->format.fmt.pix_mp.num_planes : 1; -+ unsigned int i; ++ node->format.fmt.pix_mp.num_planes : 1; + -+ for (i = 0; i < num_planes; i++) { -+ size = NODE_IS_MPLANE(node) -+ ? node->format.fmt.pix_mp.plane_fmt[i].sizeimage -+ : node->format.fmt.meta.buffersize; ++ for (unsigned int i = 0; i < num_planes; i++) { ++ unsigned long size = NODE_IS_MPLANE(node) ? ++ node->format.fmt.pix_mp.plane_fmt[i].sizeimage : ++ node->format.fmt.meta.buffersize; + + if (vb2_plane_size(vb, i) < size) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "data will not fit into plane %d (%lu < %lu)\n", + i, vb2_plane_size(vb, i), size); + return -EINVAL; @@ -129222,6 +144549,7 @@ index 000000000000..073b0e387473 + void *src = vb2_plane_vaddr(vb, 0); + + memcpy(dst, src, sizeof(struct pisp_be_tiles_config)); ++ + return pisp_be_validate_config(node->node_group, dst); + } + @@ -129248,20 +144576,21 @@ index 000000000000..073b0e387473 + * Every time we add a buffer, check if there's now some work for the hw + * to do, but only for this client. + */ -+ pispbe_schedule_one(node_group); ++ pispbe_schedule(node_group->pispbe, node_group, false); +} + +static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) +{ -+ unsigned long flags; + struct pispbe_node *node = vb2_get_drv_priv(q); + struct pispbe_node_group *node_group = node->node_group; + struct pispbe_dev *pispbe = node_group->pispbe; ++ struct pispbe_buffer *buf, *tmp; ++ unsigned long flags; + int ret; + + ret = pm_runtime_resume_and_get(pispbe->dev); + if (ret < 0) -+ return ret; ++ goto err_return_buffers; + + spin_lock_irqsave(&pispbe->hw_lock, flags); + node->node_group->streaming_map |= BIT(node->id); @@ -129274,9 +144603,19 @@ index 000000000000..073b0e387473 + node->node_group->streaming_map); + + /* Maybe we're ready to run. */ -+ pispbe_schedule_one(node_group); ++ pispbe_schedule(node_group->pispbe, node_group, false); + + return 0; ++ ++err_return_buffers: ++ spin_lock_irqsave(&pispbe->hw_lock, flags); ++ list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) { ++ list_del(&buf->ready_list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); ++ } ++ spin_unlock_irqrestore(&pispbe->hw_lock, flags); ++ ++ return ret; +} + +static void pispbe_node_stop_streaming(struct vb2_queue *q) @@ -129293,7 +144632,8 @@ index 000000000000..073b0e387473 + * partial set of buffers was queued and cannot be run. For now, just + * cancel all buffers stuck in the "ready queue", then wait for any + * running job. -+ * XXX This may return buffers out of order. ++ * ++ * This may return buffers out of order. + */ + dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); + spin_lock_irqsave(&pispbe->hw_lock, flags); @@ -129350,18 +144690,11 @@ index 000000000000..073b0e387473 + + strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver)); + strscpy(cap->card, PISPBE_NAME, sizeof(cap->card)); -+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", -+ dev_name(pispbe->dev)); -+ -+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | -+ V4L2_CAP_VIDEO_OUTPUT_MPLANE | -+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS | -+ V4L2_CAP_META_OUTPUT | V4L2_CAP_META_CAPTURE; -+ cap->device_caps = node->vfd.device_caps; + + dev_dbg(pispbe->dev, "Caps for node %s: %x and %x (dev %x)\n", + NODE_NAME(node), cap->capabilities, cap->device_caps, + node->vfd.device_caps); ++ + return 0; +} + @@ -129372,14 +144705,16 @@ index 000000000000..073b0e387473 + struct pispbe_dev *pispbe = node->node_group->pispbe; + + if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot get capture fmt for output node %s\n", + NODE_NAME(node)); + return -EINVAL; + } ++ + *f = node->format; + dev_dbg(pispbe->dev, "Get capture format for node %s\n", + NODE_NAME(node)); ++ + return 0; +} + @@ -129390,14 +144725,16 @@ index 000000000000..073b0e387473 + struct pispbe_dev *pispbe = node->node_group->pispbe; + + if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot get capture fmt for output node %s\n", + NODE_NAME(node)); + return -EINVAL; + } ++ + *f = node->format; + dev_dbg(pispbe->dev, "Get output format for node %s\n", + NODE_NAME(node)); ++ + return 0; +} + @@ -129408,95 +144745,39 @@ index 000000000000..073b0e387473 + struct pispbe_dev *pispbe = node->node_group->pispbe; + + if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot get capture fmt for meta output node %s\n", + NODE_NAME(node)); + return -EINVAL; + } ++ + *f = node->format; + dev_dbg(pispbe->dev, "Get output format for meta node %s\n", + NODE_NAME(node)); -+ return 0; -+} -+ -+static int pispbe_node_g_fmt_meta_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct pispbe_node *node = video_drvdata(file); -+ struct pispbe_dev *pispbe = node->node_group->pispbe; -+ -+ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { -+ dev_err(pispbe->dev, -+ "Cannot get capture fmt for meta output node %s\n", -+ NODE_NAME(node)); -+ return -EINVAL; -+ } -+ *f = node->format; -+ dev_dbg(pispbe->dev, "Get output format for meta node %s\n", -+ NODE_NAME(node)); -+ return 0; -+} -+ -+static int verify_be_pix_format(const struct v4l2_format *f, -+ struct pispbe_node *node) -+{ -+ struct pispbe_dev *pispbe = node->node_group->pispbe; -+ unsigned int nplanes = f->fmt.pix_mp.num_planes; -+ unsigned int i; -+ -+ if (f->fmt.pix_mp.width == 0 || f->fmt.pix_mp.height == 0) { -+ dev_err(pispbe->dev, "Details incorrect for output node %s\n", -+ NODE_NAME(node)); -+ return -EINVAL; -+ } -+ -+ if (nplanes == 0 || nplanes > MAX_PLANES) { -+ dev_err(pispbe->dev, -+ "Bad number of planes for output node %s, req =%d\n", -+ NODE_NAME(node), nplanes); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < nplanes; i++) { -+ const struct v4l2_plane_pix_format *p; -+ -+ p = &f->fmt.pix_mp.plane_fmt[i]; -+ if (p->bytesperline == 0 || p->sizeimage == 0) { -+ dev_err(pispbe->dev, -+ "Invalid plane %d for output node %s\n", -+ i, NODE_NAME(node)); -+ return -EINVAL; -+ } -+ } + + return 0; +} + -+static const struct pisp_be_format *find_format(unsigned int fourcc) ++static const struct pisp_be_format *pispbe_find_fmt(unsigned int fourcc) +{ -+ const struct pisp_be_format *fmt; -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { -+ fmt = &supported_formats[i]; -+ if (fmt->fourcc == fourcc) -+ return fmt; ++ for (unsigned int i = 0; i < ARRAY_SIZE(supported_formats); i++) { ++ if (supported_formats[i].fourcc == fourcc) ++ return &supported_formats[i]; + } + + return NULL; +} + -+static void set_plane_params(struct v4l2_format *f, -+ const struct pisp_be_format *fmt) ++static void pispbe_set_plane_params(struct v4l2_format *f, ++ const struct pisp_be_format *fmt) +{ + unsigned int nplanes = f->fmt.pix_mp.num_planes; + unsigned int total_plane_factor = 0; -+ unsigned int i; + -+ for (i = 0; i < MAX_PLANES; i++) ++ for (unsigned int i = 0; i < PISPBE_MAX_PLANES; i++) + total_plane_factor += fmt->plane_factor[i]; + -+ for (i = 0; i < nplanes; i++) { ++ for (unsigned int i = 0; i < nplanes; i++) { + struct v4l2_plane_pix_format *p = &f->fmt.pix_mp.plane_fmt[i]; + unsigned int bpl, plane_size; + @@ -129516,28 +144797,25 @@ index 000000000000..073b0e387473 + } +} + -+static int try_format(struct v4l2_format *f, struct pispbe_node *node) ++static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node) +{ + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ const struct pisp_be_format *fmt; -+ unsigned int i; -+ bool is_rgb; + u32 pixfmt = f->fmt.pix_mp.pixelformat; ++ const struct pisp_be_format *fmt; ++ bool is_rgb; + + dev_dbg(pispbe->dev, -+ "%s: [%s] req %ux%u " V4L2_FOURCC_CONV ", planes %d\n", ++ "%s: [%s] req %ux%u %p4cc, planes %d\n", + __func__, NODE_NAME(node), f->fmt.pix_mp.width, -+ f->fmt.pix_mp.height, V4L2_FOURCC_CONV_ARGS(pixfmt), ++ f->fmt.pix_mp.height, &pixfmt, + f->fmt.pix_mp.num_planes); + -+ if (pixfmt == V4L2_PIX_FMT_RPI_BE) -+ return verify_be_pix_format(f, node); -+ -+ fmt = find_format(pixfmt); ++ fmt = pispbe_find_fmt(pixfmt); + if (!fmt) { -+ dev_dbg(pispbe->dev, "%s: [%s] Format not found, defaulting to YUV420\n", ++ dev_dbg(pispbe->dev, ++ "%s: [%s] Format not found, defaulting to YUV420\n", + __func__, NODE_NAME(node)); -+ fmt = find_format(V4L2_PIX_FMT_YUV420); ++ fmt = pispbe_find_fmt(V4L2_PIX_FMT_YUV420); + } + + f->fmt.pix_mp.pixelformat = fmt->fourcc; @@ -129553,7 +144831,8 @@ index 000000000000..073b0e387473 + * not supported. This also catches the case when the "default" + * colour space was requested (as that's never in the mask). + */ -+ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) & fmt->colorspace_mask)) ++ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) & ++ fmt->colorspace_mask)) + f->fmt.pix_mp.colorspace = fmt->colorspace_default; + + /* In all cases, we only support the defaults for these: */ @@ -129568,9 +144847,9 @@ index 000000000000..073b0e387473 + f->fmt.pix_mp.ycbcr_enc); + + /* Set plane size and bytes/line for each plane. */ -+ set_plane_params(f, fmt); ++ pispbe_set_plane_params(f, fmt); + -+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ for (unsigned int i = 0; i < f->fmt.pix_mp.num_planes; i++) { + dev_dbg(pispbe->dev, + "%s: [%s] calc plane %d, %ux%u, depth %u, bpl %u size %u\n", + __func__, NODE_NAME(node), i, f->fmt.pix_mp.width, @@ -129578,8 +144857,6 @@ index 000000000000..073b0e387473 + f->fmt.pix_mp.plane_fmt[i].bytesperline, + f->fmt.pix_mp.plane_fmt[i].sizeimage); + } -+ -+ return 0; +} + +static int pispbe_node_try_fmt_vid_cap(struct file *file, void *priv, @@ -129587,18 +144864,15 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = video_drvdata(file); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret; + + if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot set capture fmt for output node %s\n", + NODE_NAME(node)); + return -EINVAL; + } + -+ ret = try_format(f, node); -+ if (ret < 0) -+ return ret; ++ pispbe_try_format(f, node); + + return 0; +} @@ -129608,18 +144882,15 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = video_drvdata(file); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret; + + if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot set capture fmt for output node %s\n", + NODE_NAME(node)); + return -EINVAL; + } + -+ ret = try_format(f, node); -+ if (ret < 0) -+ return ret; ++ pispbe_try_format(f, node); + + return 0; +} @@ -129631,7 +144902,7 @@ index 000000000000..073b0e387473 + struct pispbe_dev *pispbe = node->node_group->pispbe; + + if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) { -+ dev_err(pispbe->dev, ++ dev_dbg(pispbe->dev, + "Cannot set capture fmt for meta output node %s\n", + NODE_NAME(node)); + return -EINVAL; @@ -129643,43 +144914,26 @@ index 000000000000..073b0e387473 + return 0; +} + -+static int pispbe_node_try_fmt_meta_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct pispbe_node *node = video_drvdata(file); -+ struct pispbe_dev *pispbe = node->node_group->pispbe; -+ -+ if (!NODE_IS_META(node) || NODE_IS_OUTPUT(node)) { -+ dev_err(pispbe->dev, -+ "Cannot set capture fmt for meta output node %s\n", -+ NODE_NAME(node)); -+ return -EINVAL; -+ } -+ -+ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; -+ if (!f->fmt.meta.buffersize) -+ f->fmt.meta.buffersize = BIT(20); -+ -+ return 0; -+} -+ +static int pispbe_node_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct pispbe_node *node = video_drvdata(file); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret = pispbe_node_try_fmt_vid_cap(file, priv, f); ++ int ret; + ++ ret = pispbe_node_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + -+ node->format = *f; -+ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ if (vb2_is_busy(&node->queue)) ++ return -EBUSY; ++ ++ node->format = *f; ++ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, "Set capture format for node %s to %p4cc\n", ++ NODE_NAME(node), &f->fmt.pix_mp.pixelformat); + -+ dev_dbg(pispbe->dev, -+ "Set capture format for node %s to " V4L2_FOURCC_CONV "\n", -+ NODE_NAME(node), -+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); + return 0; +} + @@ -129688,18 +144942,21 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = video_drvdata(file); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret = pispbe_node_try_fmt_vid_out(file, priv, f); ++ int ret; + ++ ret = pispbe_node_try_fmt_vid_out(file, priv, f); + if (ret < 0) + return ret; + -+ node->format = *f; -+ node->pisp_format = find_format(f->fmt.pix_mp.pixelformat); ++ if (vb2_is_busy(&node->queue)) ++ return -EBUSY; ++ ++ node->format = *f; ++ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat); ++ ++ dev_dbg(pispbe->dev, "Set output format for node %s to %p4cc\n", ++ NODE_NAME(node), &f->fmt.pix_mp.pixelformat); + -+ dev_dbg(pispbe->dev, -+ "Set output format for node %s to " V4L2_FOURCC_CONV "\n", -+ NODE_NAME(node), -+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat)); + return 0; +} + @@ -129708,38 +144965,21 @@ index 000000000000..073b0e387473 +{ + struct pispbe_node *node = video_drvdata(file); + struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret = pispbe_node_try_fmt_meta_out(file, priv, f); ++ int ret; + ++ ret = pispbe_node_try_fmt_meta_out(file, priv, f); + if (ret < 0) + return ret; + ++ if (vb2_is_busy(&node->queue)) ++ return -EBUSY; ++ + node->format = *f; + node->pisp_format = &meta_out_supported_formats[0]; + -+ dev_dbg(pispbe->dev, -+ "Set output format for meta node %s to " V4L2_FOURCC_CONV "\n", -+ NODE_NAME(node), -+ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); -+ return 0; -+} ++ dev_dbg(pispbe->dev, "Set output format for meta node %s to %p4cc\n", ++ NODE_NAME(node), &f->fmt.meta.dataformat); + -+static int pispbe_node_s_fmt_meta_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct pispbe_node *node = video_drvdata(file); -+ struct pispbe_dev *pispbe = node->node_group->pispbe; -+ int ret = pispbe_node_try_fmt_meta_cap(file, priv, f); -+ -+ if (ret < 0) -+ return ret; -+ -+ node->format = *f; -+ node->pisp_format = find_format(f->fmt.meta.dataformat); -+ -+ dev_dbg(pispbe->dev, -+ "Set capture format for meta node %s to " V4L2_FOURCC_CONV "\n", -+ NODE_NAME(node), -+ V4L2_FOURCC_CONV_ARGS(f->fmt.meta.dataformat)); + return 0; +} + @@ -129755,10 +144995,7 @@ index 000000000000..073b0e387473 + if (f->index) + return -EINVAL; + -+ if (NODE_IS_OUTPUT(node)) -+ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG; -+ else -+ f->pixelformat = V4L2_PIX_FMT_RPI_BE; ++ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG; + f->flags = 0; + return 0; + } @@ -129781,8 +145018,8 @@ index 000000000000..073b0e387473 + if (NODE_IS_META(node) || fsize->index) + return -EINVAL; + -+ if (!find_format(fsize->pixel_format)) { -+ dev_err(pispbe->dev, "Invalid pixel code: %x\n", ++ if (!pispbe_find_fmt(fsize->pixel_format)) { ++ dev_dbg(pispbe->dev, "Invalid pixel code: %x\n", + fsize->pixel_format); + return -EINVAL; + } @@ -129799,49 +145036,19 @@ index 000000000000..073b0e387473 + return 0; +} + -+static int pispbe_node_streamon(struct file *file, void *priv, -+ enum v4l2_buf_type type) -+{ -+ struct pispbe_node *node = video_drvdata(file); -+ struct pispbe_dev *pispbe = node->node_group->pispbe; -+ -+ /* Do we need a node->stream_lock mutex? */ -+ -+ dev_dbg(pispbe->dev, "Stream on for node %s\n", NODE_NAME(node)); -+ -+ /* Do we care about the type? Each node has only one queue. */ -+ -+ INIT_LIST_HEAD(&node->ready_queue); -+ -+ /* locking should be handled by the queue->lock? */ -+ return vb2_streamon(&node->queue, type); -+} -+ -+static int pispbe_node_streamoff(struct file *file, void *priv, -+ enum v4l2_buf_type type) -+{ -+ struct pispbe_node *node = video_drvdata(file); -+ -+ return vb2_streamoff(&node->queue, type); -+} -+ +static const struct v4l2_ioctl_ops pispbe_node_ioctl_ops = { + .vidioc_querycap = pispbe_node_querycap, + .vidioc_g_fmt_vid_cap_mplane = pispbe_node_g_fmt_vid_cap, + .vidioc_g_fmt_vid_out_mplane = pispbe_node_g_fmt_vid_out, + .vidioc_g_fmt_meta_out = pispbe_node_g_fmt_meta_out, -+ .vidioc_g_fmt_meta_cap = pispbe_node_g_fmt_meta_cap, + .vidioc_try_fmt_vid_cap_mplane = pispbe_node_try_fmt_vid_cap, + .vidioc_try_fmt_vid_out_mplane = pispbe_node_try_fmt_vid_out, + .vidioc_try_fmt_meta_out = pispbe_node_try_fmt_meta_out, -+ .vidioc_try_fmt_meta_cap = pispbe_node_try_fmt_meta_cap, + .vidioc_s_fmt_vid_cap_mplane = pispbe_node_s_fmt_vid_cap, + .vidioc_s_fmt_vid_out_mplane = pispbe_node_s_fmt_vid_out, + .vidioc_s_fmt_meta_out = pispbe_node_s_fmt_meta_out, -+ .vidioc_s_fmt_meta_cap = pispbe_node_s_fmt_meta_cap, + .vidioc_enum_fmt_vid_cap = pispbe_node_enum_fmt, + .vidioc_enum_fmt_vid_out = pispbe_node_enum_fmt, -+ .vidioc_enum_fmt_meta_cap = pispbe_node_enum_fmt, + .vidioc_enum_fmt_meta_out = pispbe_node_enum_fmt, + .vidioc_enum_framesizes = pispbe_enum_framesizes, + .vidioc_create_bufs = vb2_ioctl_create_bufs, @@ -129851,8 +145058,8 @@ index 000000000000..073b0e387473 + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, -+ .vidioc_streamon = pispbe_node_streamon, -+ .vidioc_streamoff = pispbe_node_streamoff, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct video_device pispbe_videodev = { @@ -129864,7 +145071,7 @@ index 000000000000..073b0e387473 + .release = video_device_release_empty, +}; + -+static void node_set_default_format(struct pispbe_node *node) ++static void pispbe_node_def_fmt(struct pispbe_node *node) +{ + if (NODE_IS_META(node) && NODE_IS_OUTPUT(node)) { + /* Config node */ @@ -129873,38 +145080,31 @@ index 000000000000..073b0e387473 + f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG; + f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config); + f->type = node->buf_type; -+ } else if (NODE_IS_META(node) && NODE_IS_CAPTURE(node)) { -+ /* HOG output node */ -+ struct v4l2_format *f = &node->format; -+ -+ f->fmt.meta.dataformat = V4L2_PIX_FMT_RPI_BE; -+ f->fmt.meta.buffersize = BIT(20); -+ f->type = node->buf_type; + } else { -+ struct v4l2_format f = {0}; -+ -+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420; -+ f.fmt.pix_mp.width = 1920; -+ f.fmt.pix_mp.height = 1080; -+ f.type = node->buf_type; -+ try_format(&f, node); ++ struct v4l2_format f = { ++ .fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420, ++ .fmt.pix_mp.width = 1920, ++ .fmt.pix_mp.height = 1080, ++ .type = node->buf_type, ++ }; ++ pispbe_try_format(&f, node); + node->format = f; + } + -+ node->pisp_format = find_format(node->format.fmt.pix_mp.pixelformat); ++ node->pisp_format = pispbe_find_fmt(node->format.fmt.pix_mp.pixelformat); +} + +/* + * Initialise a struct pispbe_node and register it as /dev/video + * to represent one of the PiSP Back End's input or output streams. + */ -+static int -+pispbe_init_node(struct pispbe_node_group *node_group, unsigned int id) ++static int pispbe_init_node(struct pispbe_node_group *node_group, ++ unsigned int id) +{ + bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]); + struct pispbe_node *node = &node_group->node[id]; -+ struct pispbe_dev *pispbe = node_group->pispbe; + struct media_entity *entity = &node->vfd.entity; ++ struct pispbe_dev *pispbe = node_group->pispbe; + struct video_device *vdev = &node->vfd; + struct vb2_queue *q = &node->queue; + int ret; @@ -129919,7 +145119,7 @@ index 000000000000..073b0e387473 + spin_lock_init(&node->ready_lock); + + node->format.type = node->buf_type; -+ node_set_default_format(node); ++ pispbe_node_def_fmt(node); + + q->type = node->buf_type; + q->io_modes = VB2_MMAP | VB2_DMABUF; @@ -129935,7 +145135,7 @@ index 000000000000..073b0e387473 + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(pispbe->dev, "vb2_queue_init failed\n"); -+ return ret; ++ goto err_mutex_destroy; + } + + *vdev = pispbe_videodev; /* default initialization */ @@ -129977,15 +145177,18 @@ index 000000000000..073b0e387473 + if (ret) + goto err_unregister_video_dev; + -+ dev_info(pispbe->dev, -+ "%s device node registered as /dev/video%d\n", -+ NODE_NAME(node), node->vfd.num); ++ dev_dbg(pispbe->dev, "%s device node registered as /dev/video%d\n", ++ NODE_NAME(node), node->vfd.num); ++ + return 0; + +err_unregister_video_dev: + video_unregister_device(&node->vfd); +err_unregister_queue: + vb2_queue_release(&node->queue); ++err_mutex_destroy: ++ mutex_destroy(&node->node_lock); ++ mutex_destroy(&node->queue_lock); + return ret; +} + @@ -130001,7 +145204,6 @@ index 000000000000..073b0e387473 +{ + struct pispbe_dev *pispbe = node_group->pispbe; + struct v4l2_subdev *sd = &node_group->sd; -+ unsigned int i; + int ret; + + v4l2_subdev_init(sd, &pispbe_sd_ops); @@ -130010,7 +145212,7 @@ index 000000000000..073b0e387473 + sd->dev = pispbe->dev; + strscpy(sd->name, PISPBE_NAME, sizeof(sd->name)); + -+ for (i = 0; i < PISPBE_NUM_NODES; i++) ++ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) + node_group->pad[i].flags = + NODE_DESC_IS_OUTPUT(&node_desc[i]) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; @@ -130036,22 +145238,20 @@ index 000000000000..073b0e387473 + struct pispbe_node_group *node_group = &pispbe->node_group[id]; + struct v4l2_device *v4l2_dev; + struct media_device *mdev; -+ unsigned int num_registered = 0; ++ unsigned int num_regist; + int ret; + + node_group->id = id; + node_group->pispbe = pispbe; + node_group->streaming_map = 0; + -+ dev_info(pispbe->dev, "Register nodes for group %u\n", id); ++ dev_dbg(pispbe->dev, "Register nodes for group %u\n", id); + + /* Register v4l2_device and media_device */ + mdev = &node_group->mdev; + mdev->hw_revision = node_group->pispbe->hw_version; + mdev->dev = node_group->pispbe->dev; + strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model)); -+ snprintf(mdev->bus_info, sizeof(mdev->bus_info), -+ "platform:%s", dev_name(node_group->pispbe->dev)); + media_device_init(mdev); + + v4l2_dev = &node_group->v4l2_dev; @@ -130068,8 +145268,8 @@ index 000000000000..073b0e387473 + goto err_unregister_v4l2; + + /* Create device video nodes */ -+ for (; num_registered < PISPBE_NUM_NODES; num_registered++) { -+ ret = pispbe_init_node(node_group, num_registered); ++ for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) { ++ ret = pispbe_init_node(node_group, num_regist); + if (ret) + goto err_unregister_nodes; + } @@ -130094,9 +145294,9 @@ index 000000000000..073b0e387473 +err_unregister_mdev: + media_device_unregister(mdev); +err_unregister_nodes: -+ while (num_registered-- > 0) { -+ video_unregister_device(&node_group->node[num_registered].vfd); -+ vb2_queue_release(&node_group->node[num_registered].queue); ++ while (num_regist-- > 0) { ++ video_unregister_device(&node_group->node[num_regist].vfd); ++ vb2_queue_release(&node_group->node[num_regist].queue); + } + v4l2_device_unregister_subdev(&node_group->sd); + media_entity_cleanup(&node_group->sd.entity); @@ -130110,7 +145310,6 @@ index 000000000000..073b0e387473 +static void pispbe_destroy_node_group(struct pispbe_node_group *node_group) +{ + struct pispbe_dev *pispbe = node_group->pispbe; -+ int i; + + if (node_group->config) { + dma_free_coherent(node_group->pispbe->dev, @@ -130120,15 +145319,17 @@ index 000000000000..073b0e387473 + node_group->config_dma_addr); + } + -+ dev_info(pispbe->dev, "Unregister from media controller\n"); ++ dev_dbg(pispbe->dev, "Unregister from media controller\n"); + + v4l2_device_unregister_subdev(&node_group->sd); + media_entity_cleanup(&node_group->sd.entity); + media_device_unregister(&node_group->mdev); + -+ for (i = PISPBE_NUM_NODES - 1; i >= 0; i--) { ++ for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) { + video_unregister_device(&node_group->node[i].vfd); + vb2_queue_release(&node_group->node[i].queue); ++ mutex_destroy(&node_group->node[i].node_lock); ++ mutex_destroy(&node_group->node[i].queue_lock); + } + + media_device_cleanup(&node_group->mdev); @@ -130161,6 +145362,45 @@ index 000000000000..073b0e387473 + return 0; +} + ++static int pispbe_hw_init(struct pispbe_dev *pispbe) ++{ ++ u32 u; ++ ++ /* Check the HW is present and has a known version */ ++ u = pispbe_rd(pispbe, PISP_BE_VERSION_REG); ++ dev_dbg(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u); ++ pispbe->hw_version = u; ++ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712) ++ return -ENODEV; ++ ++ /* Clear leftover interrupts */ ++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, 0xFFFFFFFFu); ++ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG); ++ dev_dbg(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u); ++ ++ pispbe->done = (uint8_t)u; ++ pispbe->started = (uint8_t)(u >> 8); ++ u = pispbe_rd(pispbe, PISP_BE_STATUS_REG); ++ dev_dbg(pispbe->dev, "pispbe_probe: Status: 0x%08x", u); ++ ++ if (u != 0 || pispbe->done != pispbe->started) { ++ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n"); ++ return -EBUSY; ++ } ++ ++ /* ++ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011 ++ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts ++ * and AXI AWID/BID variability (on versions which support this). ++ */ ++ pispbe_wr(pispbe, PISP_BE_AXI_REG, 0x32703200u); ++ ++ /* Enable both interrupt flags */ ++ pispbe_wr(pispbe, PISP_BE_INTERRUPT_EN_REG, 0x00000003u); ++ ++ return 0; ++} ++ +/* + * Probe the ISP-BE hardware block, as a single platform device. + * This will instantiate multiple "node groups" each with many device nodes. @@ -130212,15 +145452,15 @@ index 000000000000..073b0e387473 + pm_runtime_use_autosuspend(pispbe->dev); + pm_runtime_enable(pispbe->dev); + -+ ret = pm_runtime_resume_and_get(pispbe->dev); ++ ret = pispbe_runtime_resume(pispbe->dev); + if (ret) + goto pm_runtime_disable_err; + -+ pispbe->hw_busy = 0; ++ pispbe->hw_busy = false; + spin_lock_init(&pispbe->hw_lock); -+ ret = hw_init(pispbe); ++ ret = pispbe_hw_init(pispbe); + if (ret) -+ goto pm_runtime_put_err; ++ goto pm_runtime_suspend_err; + + /* + * Initialise and register devices for each node_group, including media @@ -130242,25 +145482,23 @@ index 000000000000..073b0e387473 +disable_nodes_err: + while (num_groups-- > 0) + pispbe_destroy_node_group(&pispbe->node_group[num_groups]); -+pm_runtime_put_err: -+ pm_runtime_put(pispbe->dev); ++pm_runtime_suspend_err: ++ pispbe_runtime_suspend(pispbe->dev); +pm_runtime_disable_err: + pm_runtime_dont_use_autosuspend(pispbe->dev); + pm_runtime_disable(pispbe->dev); + -+ dev_err(&pdev->dev, "%s: returning %d", __func__, ret); -+ + return ret; +} + +static int pispbe_remove(struct platform_device *pdev) +{ + struct pispbe_dev *pispbe = platform_get_drvdata(pdev); -+ int i; + -+ for (i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--) ++ for (int i = PISPBE_NUM_NODE_GROUPS - 1; i >= 0; i--) + pispbe_destroy_node_group(&pispbe->node_group[i]); + ++ pispbe_runtime_suspend(pispbe->dev); + pm_runtime_dont_use_autosuspend(pispbe->dev); + pm_runtime_disable(pispbe->dev); + @@ -130290,548 +145528,14 @@ index 000000000000..073b0e387473 +}; + +module_platform_driver(pispbe_pdrv); -diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h -new file mode 100644 -index 000000000000..bddb6e5d4670 ---- /dev/null -+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_config.h -@@ -0,0 +1,533 @@ -+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ -+/* -+ * PiSP Back End configuration definitions. -+ * -+ * Copyright (C) 2021 - Raspberry Pi Ltd -+ * -+ */ -+#ifndef _PISP_BE_CONFIG_H_ -+#define _PISP_BE_CONFIG_H_ + -+#include -+ -+#include -+ -+/* byte alignment for inputs */ -+#define PISP_BACK_END_INPUT_ALIGN 4u -+/* alignment for compressed inputs */ -+#define PISP_BACK_END_COMPRESSED_ALIGN 8u -+/* minimum required byte alignment for outputs */ -+#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u -+/* preferred byte alignment for outputs */ -+#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u -+ -+/* minimum allowed tile width anywhere in the pipeline */ -+#define PISP_BACK_END_MIN_TILE_WIDTH 16u -+/* minimum allowed tile width anywhere in the pipeline */ -+#define PISP_BACK_END_MIN_TILE_HEIGHT 16u -+ -+#define PISP_BACK_END_NUM_OUTPUTS 2 -+#define PISP_BACK_END_HOG_OUTPUT 1 -+ -+#define PISP_BACK_END_NUM_TILES 64 -+ -+enum pisp_be_bayer_enable { -+ PISP_BE_BAYER_ENABLE_INPUT = 0x000001, -+ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002, -+ PISP_BE_BAYER_ENABLE_DPC = 0x000004, -+ PISP_BE_BAYER_ENABLE_GEQ = 0x000008, -+ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010, -+ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020, -+ PISP_BE_BAYER_ENABLE_TDN = 0x000040, -+ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080, -+ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100, -+ PISP_BE_BAYER_ENABLE_SDN = 0x000200, -+ PISP_BE_BAYER_ENABLE_BLC = 0x000400, -+ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800, -+ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000, -+ PISP_BE_BAYER_ENABLE_STITCH = 0x002000, -+ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000, -+ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000, -+ PISP_BE_BAYER_ENABLE_WBG = 0x010000, -+ PISP_BE_BAYER_ENABLE_CDN = 0x020000, -+ PISP_BE_BAYER_ENABLE_LSC = 0x040000, -+ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000, -+ PISP_BE_BAYER_ENABLE_CAC = 0x100000, -+ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000, -+ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000, -+}; -+ -+enum pisp_be_rgb_enable { -+ PISP_BE_RGB_ENABLE_INPUT = 0x000001, -+ PISP_BE_RGB_ENABLE_CCM = 0x000002, -+ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004, -+ PISP_BE_RGB_ENABLE_YCBCR = 0x000008, -+ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010, -+ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020, -+ /* Preferred colours would occupy 0x000040 */ -+ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080, -+ PISP_BE_RGB_ENABLE_GAMMA = 0x000100, -+ PISP_BE_RGB_ENABLE_CSC0 = 0x000200, -+ PISP_BE_RGB_ENABLE_CSC1 = 0x000400, -+ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000, -+ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000, -+ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000, -+ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000, -+ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000, -+ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000, -+ PISP_BE_RGB_ENABLE_HOG = 0x200000 -+}; -+ -+#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i)) -+#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i)) -+#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i)) -+#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i)) -+ -+/* -+ * We use the enable flags to show when blocks are "dirty", but we need some -+ * extra ones too. -+ */ -+enum pisp_be_dirty { -+ PISP_BE_DIRTY_GLOBAL = 0x0001, -+ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002, -+ PISP_BE_DIRTY_CROP = 0x0004 -+}; -+ -+struct pisp_be_global_config { -+ u32 bayer_enables; -+ u32 rgb_enables; -+ u8 bayer_order; -+ u8 pad[3]; -+}; -+ -+struct pisp_be_input_buffer_config { -+ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */ -+ u32 addr[3][2]; -+}; -+ -+struct pisp_be_dpc_config { -+ u8 coeff_level; -+ u8 coeff_range; -+ u8 pad; -+#define PISP_BE_DPC_FLAG_FOLDBACK 1 -+ u8 flags; -+}; -+ -+struct pisp_be_geq_config { -+ u16 offset; -+#define PISP_BE_GEQ_SHARPER BIT(15) -+#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1) -+ /* top bit is the "sharper" flag, slope value is bottom 10 bits */ -+ u16 slope_sharper; -+ u16 min; -+ u16 max; -+}; -+ -+struct pisp_be_tdn_input_buffer_config { -+ /* low 32 bits followed by high 32 bits */ -+ u32 addr[2]; -+}; -+ -+struct pisp_be_tdn_config { -+ u16 black_level; -+ u16 ratio; -+ u16 noise_constant; -+ u16 noise_slope; -+ u16 threshold; -+ u8 reset; -+ u8 pad; -+}; -+ -+struct pisp_be_tdn_output_buffer_config { -+ /* low 32 bits followed by high 32 bits */ -+ u32 addr[2]; -+}; -+ -+struct pisp_be_sdn_config { -+ u16 black_level; -+ u8 leakage; -+ u8 pad; -+ u16 noise_constant; -+ u16 noise_slope; -+ u16 noise_constant2; -+ u16 noise_slope2; -+}; -+ -+struct pisp_be_stitch_input_buffer_config { -+ /* low 32 bits followed by high 32 bits */ -+ u32 addr[2]; -+}; -+ -+#define PISP_BE_STITCH_STREAMING_LONG 0x8000 -+#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff -+ -+struct pisp_be_stitch_config { -+ u16 threshold_lo; -+ u8 threshold_diff_power; -+ u8 pad; -+ -+ /* top bit indicates whether streaming input is the long exposure */ -+ u16 exposure_ratio; -+ -+ u8 motion_threshold_256; -+ u8 motion_threshold_recip; -+}; -+ -+struct pisp_be_stitch_output_buffer_config { -+ /* low 32 bits followed by high 32 bits */ -+ u32 addr[2]; -+}; -+ -+struct pisp_be_cdn_config { -+ u16 thresh; -+ u8 iir_strength; -+ u8 g_adjust; -+}; -+ -+#define PISP_BE_LSC_LOG_GRID_SIZE 5 -+#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE) -+#define PISP_BE_LSC_STEP_PRECISION 18 -+ -+struct pisp_be_lsc_config { -+ /* (1<<18) / grid_cell_width */ -+ u16 grid_step_x; -+ /* (1<<18) / grid_cell_height */ -+ u16 grid_step_y; -+ /* RGB gains jointly encoded in 32 bits */ -+ u32 lut_packed[PISP_BE_LSC_GRID_SIZE + 1] -+ [PISP_BE_LSC_GRID_SIZE + 1]; -+}; -+ -+struct pisp_be_lsc_extra { -+ u16 offset_x; -+ u16 offset_y; -+}; -+ -+#define PISP_BE_CAC_LOG_GRID_SIZE 3 -+#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE) -+#define PISP_BE_CAC_STEP_PRECISION 20 -+ -+struct pisp_be_cac_config { -+ /* (1<<20) / grid_cell_width */ -+ u16 grid_step_x; -+ /* (1<<20) / grid_cell_height */ -+ u16 grid_step_y; -+ /* [gridy][gridx][rb][xy] */ -+ s8 lut[PISP_BE_CAC_GRID_SIZE + 1][PISP_BE_CAC_GRID_SIZE + 1][2][2]; -+}; -+ -+struct pisp_be_cac_extra { -+ u16 offset_x; -+ u16 offset_y; -+}; -+ -+#define PISP_BE_DEBIN_NUM_COEFFS 4 -+ -+struct pisp_be_debin_config { -+ s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS]; -+ s8 h_enable; -+ s8 v_enable; -+ s8 pad[2]; -+}; -+ -+#define PISP_BE_TONEMAP_LUT_SIZE 64 -+ -+struct pisp_be_tonemap_config { -+ u16 detail_constant; -+ u16 detail_slope; -+ u16 iir_strength; -+ u16 strength; -+ u32 lut[PISP_BE_TONEMAP_LUT_SIZE]; -+}; -+ -+struct pisp_be_demosaic_config { -+ u8 sharper; -+ u8 fc_mode; -+ u8 pad[2]; -+}; -+ -+struct pisp_be_ccm_config { -+ s16 coeffs[9]; -+ u8 pad[2]; -+ s32 offsets[3]; -+}; -+ -+struct pisp_be_sat_control_config { -+ u8 shift_r; -+ u8 shift_g; -+ u8 shift_b; -+ u8 pad; -+}; -+ -+struct pisp_be_false_colour_config { -+ u8 distance; -+ u8 pad[3]; -+}; -+ -+#define PISP_BE_SHARPEN_SIZE 5 -+#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9 -+ -+struct pisp_be_sharpen_config { -+ s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; -+ s8 pad0[3]; -+ s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; -+ s8 pad1[3]; -+ s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; -+ s8 pad2[3]; -+ s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; -+ s8 pad3[3]; -+ s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; -+ s8 pad4[3]; -+ u16 threshold_offset0; -+ u16 threshold_slope0; -+ u16 scale0; -+ u16 pad5; -+ u16 threshold_offset1; -+ u16 threshold_slope1; -+ u16 scale1; -+ u16 pad6; -+ u16 threshold_offset2; -+ u16 threshold_slope2; -+ u16 scale2; -+ u16 pad7; -+ u16 threshold_offset3; -+ u16 threshold_slope3; -+ u16 scale3; -+ u16 pad8; -+ u16 threshold_offset4; -+ u16 threshold_slope4; -+ u16 scale4; -+ u16 pad9; -+ u16 positive_strength; -+ u16 positive_pre_limit; -+ u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; -+ u16 positive_limit; -+ u16 negative_strength; -+ u16 negative_pre_limit; -+ u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; -+ u16 negative_limit; -+ u8 enables; -+ u8 white; -+ u8 black; -+ u8 grey; -+}; -+ -+struct pisp_be_sh_fc_combine_config { -+ u8 y_factor; -+ u8 c1_factor; -+ u8 c2_factor; -+ u8 pad; -+}; -+ -+#define PISP_BE_GAMMA_LUT_SIZE 64 -+ -+struct pisp_be_gamma_config { -+ u32 lut[PISP_BE_GAMMA_LUT_SIZE]; -+}; -+ -+struct pisp_be_crop_config { -+ u16 offset_x, offset_y; -+ u16 width, height; -+}; -+ -+#define PISP_BE_RESAMPLE_FILTER_SIZE 96 -+ -+struct pisp_be_resample_config { -+ u16 scale_factor_h, scale_factor_v; -+ s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE]; -+}; -+ -+struct pisp_be_resample_extra { -+ u16 scaled_width; -+ u16 scaled_height; -+ s16 initial_phase_h[3]; -+ s16 initial_phase_v[3]; -+}; -+ -+struct pisp_be_downscale_config { -+ u16 scale_factor_h; -+ u16 scale_factor_v; -+ u16 scale_recip_h; -+ u16 scale_recip_v; -+}; -+ -+struct pisp_be_downscale_extra { -+ u16 scaled_width; -+ u16 scaled_height; -+}; -+ -+struct pisp_be_hog_config { -+ u8 compute_signed; -+ u8 channel_mix[3]; -+ u32 stride; -+}; -+ -+struct pisp_be_axi_config { -+ u8 r_qos; /* Read QoS */ -+ u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */ -+ u8 w_qos; /* Write QoS */ -+ u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */ -+}; -+ -+enum pisp_be_transform { -+ PISP_BE_TRANSFORM_NONE = 0x0, -+ PISP_BE_TRANSFORM_HFLIP = 0x1, -+ PISP_BE_TRANSFORM_VFLIP = 0x2, -+ PISP_BE_TRANSFORM_ROT180 = -+ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP) -+}; -+ -+struct pisp_be_output_format_config { -+ struct pisp_image_format_config image; -+ u8 transform; -+ u8 pad[3]; -+ u16 lo; -+ u16 hi; -+ u16 lo2; -+ u16 hi2; -+}; -+ -+struct pisp_be_output_buffer_config { -+ /* low 32 bits followed by high 32 bits (for each of 3 planes) */ -+ u32 addr[3][2]; -+}; -+ -+struct pisp_be_hog_buffer_config { -+ /* low 32 bits followed by high 32 bits */ -+ u32 addr[2]; -+}; -+ -+struct pisp_be_config { -+ /* I/O configuration: */ -+ struct pisp_be_input_buffer_config input_buffer; -+ struct pisp_be_tdn_input_buffer_config tdn_input_buffer; -+ struct pisp_be_stitch_input_buffer_config stitch_input_buffer; -+ struct pisp_be_tdn_output_buffer_config tdn_output_buffer; -+ struct pisp_be_stitch_output_buffer_config stitch_output_buffer; -+ struct pisp_be_output_buffer_config -+ output_buffer[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_hog_buffer_config hog_buffer; -+ /* Processing configuration: */ -+ struct pisp_be_global_config global; -+ struct pisp_image_format_config input_format; -+ struct pisp_decompress_config decompress; -+ struct pisp_be_dpc_config dpc; -+ struct pisp_be_geq_config geq; -+ struct pisp_image_format_config tdn_input_format; -+ struct pisp_decompress_config tdn_decompress; -+ struct pisp_be_tdn_config tdn; -+ struct pisp_compress_config tdn_compress; -+ struct pisp_image_format_config tdn_output_format; -+ struct pisp_be_sdn_config sdn; -+ struct pisp_bla_config blc; -+ struct pisp_compress_config stitch_compress; -+ struct pisp_image_format_config stitch_output_format; -+ struct pisp_image_format_config stitch_input_format; -+ struct pisp_decompress_config stitch_decompress; -+ struct pisp_be_stitch_config stitch; -+ struct pisp_be_lsc_config lsc; -+ struct pisp_wbg_config wbg; -+ struct pisp_be_cdn_config cdn; -+ struct pisp_be_cac_config cac; -+ struct pisp_be_debin_config debin; -+ struct pisp_be_tonemap_config tonemap; -+ struct pisp_be_demosaic_config demosaic; -+ struct pisp_be_ccm_config ccm; -+ struct pisp_be_sat_control_config sat_control; -+ struct pisp_be_ccm_config ycbcr; -+ struct pisp_be_sharpen_config sharpen; -+ struct pisp_be_false_colour_config false_colour; -+ struct pisp_be_sh_fc_combine_config sh_fc_combine; -+ struct pisp_be_ccm_config ycbcr_inverse; -+ struct pisp_be_gamma_config gamma; -+ struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_output_format_config -+ output_format[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_hog_config hog; -+ struct pisp_be_axi_config axi; -+ /* Non-register fields: */ -+ struct pisp_be_lsc_extra lsc_extra; -+ struct pisp_be_cac_extra cac_extra; -+ struct pisp_be_downscale_extra -+ downscale_extra[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS]; -+ struct pisp_be_crop_config crop; -+ struct pisp_image_format_config hog_format; -+ u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ -+ u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ -+ u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ -+}; -+ -+/* -+ * We also need a tile structure to describe the size of the tiles going -+ * through the pipeline. -+ */ -+ -+enum pisp_tile_edge { -+ PISP_LEFT_EDGE = (1 << 0), -+ PISP_RIGHT_EDGE = (1 << 1), -+ PISP_TOP_EDGE = (1 << 2), -+ PISP_BOTTOM_EDGE = (1 << 3) -+}; -+ -+struct pisp_tile { -+ u8 edge; // enum pisp_tile_edge -+ u8 pad0[3]; -+ // 4 bytes -+ u32 input_addr_offset; -+ u32 input_addr_offset2; -+ u16 input_offset_x; -+ u16 input_offset_y; -+ u16 input_width; -+ u16 input_height; -+ // 20 bytes -+ u32 tdn_input_addr_offset; -+ u32 tdn_output_addr_offset; -+ u32 stitch_input_addr_offset; -+ u32 stitch_output_addr_offset; -+ // 36 bytes -+ u32 lsc_grid_offset_x; -+ u32 lsc_grid_offset_y; -+ // 44 bytes -+ u32 cac_grid_offset_x; -+ u32 cac_grid_offset_y; -+ // 52 bytes -+ u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS]; -+ // 68 bytes -+ /* Ordering is planes then branches */ -+ u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; -+ u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; -+ // 92 bytes -+ u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS]; -+ // 100 bytes -+ /* Ordering is planes then branches */ -+ u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; -+ u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; -+ // 124 bytes -+ u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 output_width[PISP_BACK_END_NUM_OUTPUTS]; -+ u16 output_height[PISP_BACK_END_NUM_OUTPUTS]; -+ // 140 bytes -+ u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS]; -+ u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS]; -+ // 156 bytes -+ u32 output_hog_addr_offset; -+ // 160 bytes -+}; -+ -+static_assert(sizeof(struct pisp_tile) == 160); -+ -+struct pisp_be_tiles_config { -+ struct pisp_be_config config; -+ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES]; -+ int num_tiles; -+}; -+ -+#endif /* _PISP_BE_CONFIG_H_ */ ++MODULE_DESCRIPTION("PiSP Back End driver"); ++MODULE_AUTHOR("David Plowman "); ++MODULE_AUTHOR("Nick Hollinghurst "); ++MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h new file mode 100644 -index 000000000000..4e2b94475adf +index 000000000000..b5cb7b8c7531 --- /dev/null +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h @@ -0,0 +1,519 @@ @@ -130839,7 +145543,7 @@ index 000000000000..4e2b94475adf +/* + * PiSP Back End driver image format definitions. + * -+ * Copyright (c) 2021 Raspberry Pi Ltd ++ * Copyright (c) 2021-2024 Raspberry Pi Ltd + */ + +#ifndef _PISP_BE_FORMATS_ @@ -130848,15 +145552,15 @@ index 000000000000..4e2b94475adf +#include +#include + -+#define MAX_PLANES 3 -+#define P3(x) ((x) * 8) ++#define PISPBE_MAX_PLANES 3 ++#define P3(x) ((x) * 8) + +struct pisp_be_format { + unsigned int fourcc; + unsigned int align; + unsigned int bit_depth; + /* 0P3 factor for plane sizing */ -+ unsigned int plane_factor[MAX_PLANES]; ++ unsigned int plane_factor[PISPBE_MAX_PLANES]; + unsigned int num_planes; + unsigned int colorspace_mask; + enum v4l2_colorspace colorspace_default; @@ -130864,14 +145568,19 @@ index 000000000000..4e2b94475adf + +#define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace) + -+#define V4L2_COLORSPACE_MASK_JPEG V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) -+#define V4L2_COLORSPACE_MASK_SMPTE170M V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) -+#define V4L2_COLORSPACE_MASK_REC709 V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) -+#define V4L2_COLORSPACE_MASK_SRGB V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) -+#define V4L2_COLORSPACE_MASK_RAW V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) ++#define V4L2_COLORSPACE_MASK_JPEG \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG) ++#define V4L2_COLORSPACE_MASK_SMPTE170M \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M) ++#define V4L2_COLORSPACE_MASK_REC709 \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709) ++#define V4L2_COLORSPACE_MASK_SRGB \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB) ++#define V4L2_COLORSPACE_MASK_RAW \ ++ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW) + +/* -+ * All three colour spaces JPEG, SMPTE170M and REC709 are fundamentally sRGB ++ * All three colour spaces SRGB, SMPTE170M and REC709 are fundamentally sRGB + * underneath (as near as makes no difference to us), just with different YCbCr + * encodings. Therefore the ISP can generate sRGB on its main output and any of + * the others on its low resolution output. Applications should, when using both @@ -130880,9 +145589,9 @@ index 000000000000..4e2b94475adf + * producing an RGB format. In turn this requires us to allow all these colour + * spaces for every YUV/RGB output format. + */ -+#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ -+ V4L2_COLORSPACE_MASK_SRGB | \ -+ V4L2_COLORSPACE_MASK_SMPTE170M | \ ++#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \ ++ V4L2_COLORSPACE_MASK_SRGB | \ ++ V4L2_COLORSPACE_MASK_SMPTE170M | \ + V4L2_COLORSPACE_MASK_REC709) + +static const struct pisp_be_format supported_formats[] = { @@ -130895,7 +145604,7 @@ index 000000000000..4e2b94475adf + .plane_factor = { P3(1), P3(0.25), P3(0.25) }, + .num_planes = 1, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, -+ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, @@ -130969,7 +145678,7 @@ index 000000000000..4e2b94475adf + .plane_factor = { P3(1), P3(0.25), P3(0.25) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, -+ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, @@ -131005,7 +145714,7 @@ index 000000000000..4e2b94475adf + .plane_factor = { P3(1), P3(0.5), P3(0.5) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, -+ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU422M, @@ -131023,7 +145732,7 @@ index 000000000000..4e2b94475adf + .plane_factor = { P3(1), P3(1), P3(1) }, + .num_planes = 3, + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, -+ .colorspace_default = V4L2_COLORSPACE_JPEG, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, + { + .fourcc = V4L2_PIX_FMT_YVU444M, @@ -131339,11 +146048,6 @@ index 000000000000..4e2b94475adf + .colorspace_mask = V4L2_COLORSPACE_MASK_RAW, + .colorspace_default = V4L2_COLORSPACE_RAW, + }, -+ /* Opaque BE format for HW verification. */ -+ { -+ .fourcc = V4L2_PIX_FMT_RPI_BE, -+ .align = 32, -+ }, +}; + +static const struct pisp_be_format meta_out_supported_formats[] = { @@ -136332,7 +151036,7 @@ index 000000000000..93d2d3c27a56 + +#endif /* _PISP_FE_TYPES_H_ */ diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c -index 5de6b6694f53..a504a69ea25f 100644 +index 5de6b6694f53..ea6d094e0844 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -20,10 +20,27 @@ @@ -136363,7 +151067,59 @@ index 5de6b6694f53..a504a69ea25f 100644 struct mux_control *mux; struct mutex lock; int active; -@@ -301,10 +318,34 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd, +@@ -52,6 +69,8 @@ static int video_mux_link_setup(struct media_entity *entity, + const struct media_pad *remote, u32 flags) + { + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); ++ struct v4l2_subdev *source_sd; ++ struct v4l2_subdev_state *sd_state; + struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); + u16 source_pad = entity->num_pads - 1; + int ret = 0; +@@ -67,10 +86,10 @@ static int video_mux_link_setup(struct media_entity *entity, + remote->entity->name, remote->index, local->entity->name, + local->index, flags & MEDIA_LNK_FL_ENABLED); + ++ sd_state = v4l2_subdev_lock_and_get_active_state(sd); + mutex_lock(&vmux->lock); + + if (flags & MEDIA_LNK_FL_ENABLED) { +- struct v4l2_subdev_state *sd_state; + struct v4l2_mbus_framefmt *source_mbusformat; + + if (vmux->active == local->index) +@@ -88,12 +107,14 @@ static int video_mux_link_setup(struct media_entity *entity, + vmux->active = local->index; + + /* Propagate the active format to the source */ +- sd_state = v4l2_subdev_lock_and_get_active_state(sd); + source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, + source_pad); + *source_mbusformat = *v4l2_subdev_get_pad_format(sd, sd_state, + vmux->active); +- v4l2_subdev_unlock_state(sd_state); ++ ++ source_sd = media_entity_to_v4l2_subdev(remote->entity); ++ vmux->subdev.ctrl_handler = source_sd->ctrl_handler; ++ + } else { + if (vmux->active != local->index) + goto out; +@@ -101,10 +122,13 @@ static int video_mux_link_setup(struct media_entity *entity, + dev_dbg(sd->dev, "going inactive\n"); + mux_control_deselect(vmux->mux); + vmux->active = -1; ++ ++ vmux->subdev.ctrl_handler = NULL; + } + + out: + mutex_unlock(&vmux->lock); ++ v4l2_subdev_unlock_state(sd_state); + return ret; + } + +@@ -301,10 +325,34 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd, return 0; } @@ -136398,7 +151154,7 @@ index 5de6b6694f53..a504a69ea25f 100644 }; static const struct v4l2_subdev_ops video_mux_subdev_ops = { -@@ -317,6 +358,9 @@ static int video_mux_notify_bound(struct v4l2_async_notifier *notifier, +@@ -317,6 +365,9 @@ static int video_mux_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_async_connection *asd) { struct video_mux *vmux = notifier_to_video_mux(notifier); @@ -136408,7 +151164,7 @@ index 5de6b6694f53..a504a69ea25f 100644 return v4l2_create_fwnode_links(sd, &vmux->subdev); } -@@ -334,7 +378,7 @@ static int video_mux_async_register(struct video_mux *vmux, +@@ -334,7 +385,7 @@ static int video_mux_async_register(struct video_mux *vmux, v4l2_async_subdev_nf_init(&vmux->notifier, &vmux->subdev); for (i = 0; i < num_input_pads; i++) { @@ -136417,7 +151173,7 @@ index 5de6b6694f53..a504a69ea25f 100644 struct fwnode_handle *ep, *remote_ep; ep = fwnode_graph_get_endpoint_by_id( -@@ -352,8 +396,7 @@ static int video_mux_async_register(struct video_mux *vmux, +@@ -352,8 +403,7 @@ static int video_mux_async_register(struct video_mux *vmux, fwnode_handle_put(remote_ep); asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep, @@ -136427,7 +151183,7 @@ index 5de6b6694f53..a504a69ea25f 100644 fwnode_handle_put(ep); if (IS_ERR(asd)) { -@@ -362,6 +405,8 @@ static int video_mux_async_register(struct video_mux *vmux, +@@ -362,6 +412,8 @@ static int video_mux_async_register(struct video_mux *vmux, if (ret != -EEXIST) goto err_nf_cleanup; } @@ -136436,7 +151192,7 @@ index 5de6b6694f53..a504a69ea25f 100644 } vmux->notifier.ops = &video_mux_notify_ops; -@@ -387,6 +432,9 @@ static int video_mux_probe(struct platform_device *pdev) +@@ -387,6 +439,9 @@ static int video_mux_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; @@ -136446,7 +151202,7 @@ index 5de6b6694f53..a504a69ea25f 100644 struct device_node *ep; struct video_mux *vmux; unsigned int num_pads = 0; -@@ -433,10 +481,27 @@ static int video_mux_probe(struct platform_device *pdev) +@@ -433,10 +488,27 @@ static int video_mux_probe(struct platform_device *pdev) if (!vmux->pads) return -ENOMEM; @@ -136488,7 +151244,7 @@ index 07bdf649c60d..75186e63322c 100644 help Say Y if you want to use a PWM based IR transmitter. This is diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c -index 7732054c4621..f8fdbc83b7e8 100644 +index 4a6fafe7a249..f8fdbc83b7e8 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -10,6 +10,8 @@ @@ -136528,22 +151284,7 @@ index 7732054c4621..f8fdbc83b7e8 100644 { struct pwm_ir *pwm_ir = dev->priv; struct pwm_device *pwm = pwm_ir->pwm; -@@ -67,7 +75,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, - - for (i = 0; i < count; i++) { - state.enabled = !(i % 2); -- pwm_apply_state(pwm, &state); -+ pwm_apply_might_sleep(pwm, &state); - - edge = ktime_add_us(edge, txbuf[i]); - delta = ktime_us_delta(edge, ktime_get()); -@@ -76,11 +84,67 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, - } - - state.enabled = false; -- pwm_apply_state(pwm, &state); -+ pwm_apply_might_sleep(pwm, &state); - +@@ -81,6 +89,62 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, return count; } @@ -136654,6 +151395,19 @@ index f7884bb56fcc..b0a2fd7e13aa 100644 { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03, &rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A, +diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c +index 3a4b15a98e02..33b277014372 100644 +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -253,6 +253,8 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) + { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, ++ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, ++ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + + /* YUV packed formats */ diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 8696eb1cdd61..6d826474fe57 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -136755,25 +151509,10 @@ index 8db9ac9c1433..c21ddbbfa50e 100644 schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 6b653487d954..cc9eae073fc1 100644 +index 6b653487d954..8e29244ef05f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig -@@ -11,6 +11,14 @@ config MFD_CORE - select IRQ_DOMAIN - default n - -+config MFD_RPISENSE_CORE -+ tristate "Raspberry Pi Sense HAT core functions" -+ depends on I2C -+ select MFD_CORE -+ help -+ This is the core driver for the Raspberry Pi Sense HAT. This provides -+ the necessary functions to communicate with the hardware. -+ - config MFD_CS5535 - tristate "AMD CS5535 and CS5536 southbridge core functions" - select MFD_CORE -@@ -1178,6 +1186,16 @@ config MFD_SY7636A +@@ -1178,6 +1178,16 @@ config MFD_SY7636A To enable support for building sub-devices as modules, choose M here. @@ -136790,7 +151529,7 @@ index 6b653487d954..cc9eae073fc1 100644 config MFD_RDC321X tristate "RDC R-321x southbridge" select MFD_CORE -@@ -2321,6 +2339,17 @@ config MFD_INTEL_M10_BMC_PMCI +@@ -2321,6 +2331,17 @@ config MFD_INTEL_M10_BMC_PMCI additional drivers must be enabled in order to use the functionality of the device. @@ -136809,22 +151548,14 @@ index 6b653487d954..cc9eae073fc1 100644 tristate "Renesas Synchronization Management Unit with I2C" depends on I2C && OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 700b3600eb79..3eff03c6d6ba 100644 +index 50b42df268ea..e131b7ed5ca4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile -@@ -268,6 +268,7 @@ obj-$(CONFIG_MFD_STMFX) += stmfx.o - obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o - obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o - obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o -+obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o +@@ -285,3 +285,5 @@ obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o - obj-$(CONFIG_LPC_CHIP3) += lpc_sunway_chip3.o - obj-$(CONFIG_SUNWAY_SUPERIO_AST2400) += sunway_ast2400.o -@@ -287,3 +288,5 @@ rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o - rsmu-spi-objs := rsmu_core.o rsmu_spi.o - obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o - obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o -+ + obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o + obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o ++ +obj-$(CONFIG_MFD_RP1) += rp1.o diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c index 3cb2b9423121..8b31775da7b6 100644 @@ -137266,177 +151997,8 @@ index 000000000000..0a498a670a81 +MODULE_AUTHOR("Phil Elwell "); +MODULE_DESCRIPTION("RP1 wrapper"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/mfd/rpisense-core.c b/drivers/mfd/rpisense-core.c -new file mode 100644 -index 000000000000..87a319525a0f ---- /dev/null -+++ b/drivers/mfd/rpisense-core.c -@@ -0,0 +1,163 @@ -+/* -+ * Raspberry Pi Sense HAT core driver -+ * http://raspberrypi.org -+ * -+ * Copyright (C) 2015 Raspberry Pi -+ * -+ * Author: Serge Schneider -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * This driver is based on wm8350 implementation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static struct rpisense *rpisense; -+ -+static void rpisense_client_dev_register(struct rpisense *rpisense, -+ const char *name, -+ struct platform_device **pdev) -+{ -+ int ret; -+ -+ *pdev = platform_device_alloc(name, -1); -+ if (*pdev == NULL) { -+ dev_err(rpisense->dev, "Failed to allocate %s\n", name); -+ return; -+ } -+ -+ (*pdev)->dev.parent = rpisense->dev; -+ platform_set_drvdata(*pdev, rpisense); -+ ret = platform_device_add(*pdev); -+ if (ret != 0) { -+ dev_err(rpisense->dev, "Failed to register %s: %d\n", -+ name, ret); -+ platform_device_put(*pdev); -+ *pdev = NULL; -+ } -+} -+ -+static int rpisense_probe(struct i2c_client *i2c) -+{ -+ int ret; -+ struct rpisense_js *rpisense_js; -+ -+ rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL); -+ if (rpisense == NULL) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(i2c, rpisense); -+ rpisense->dev = &i2c->dev; -+ rpisense->i2c_client = i2c; -+ -+ ret = rpisense_reg_read(rpisense, RPISENSE_WAI); -+ if (ret > 0) { -+ if (ret != 's') -+ return -EINVAL; -+ } else { -+ return ret; -+ } -+ ret = rpisense_reg_read(rpisense, RPISENSE_VER); -+ if (ret < 0) -+ return ret; -+ -+ dev_info(rpisense->dev, -+ "Raspberry Pi Sense HAT firmware version %i\n", ret); -+ -+ rpisense_js = &rpisense->joystick; -+ rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev, -+ "keys-int", GPIOD_IN); -+ if (IS_ERR(rpisense_js->keys_desc)) { -+ dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n"); -+ rpisense_js->keys_desc = gpio_to_desc(23); -+ if (rpisense_js->keys_desc == NULL) { -+ dev_err(&i2c->dev, "GPIO23 fallback failed.\n"); -+ return PTR_ERR(rpisense_js->keys_desc); -+ } -+ } -+ rpisense_client_dev_register(rpisense, "rpi-sense-js", -+ &(rpisense->joystick.pdev)); -+ rpisense_client_dev_register(rpisense, "rpi-sense-fb", -+ &(rpisense->framebuffer.pdev)); -+ -+ return 0; -+} -+ -+static void rpisense_remove(struct i2c_client *i2c) -+{ -+ struct rpisense *rpisense = i2c_get_clientdata(i2c); -+ -+ platform_device_unregister(rpisense->joystick.pdev); -+} -+ -+struct rpisense *rpisense_get_dev(void) -+{ -+ return rpisense; -+} -+EXPORT_SYMBOL_GPL(rpisense_get_dev); -+ -+s32 rpisense_reg_read(struct rpisense *rpisense, int reg) -+{ -+ int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg); -+ -+ if (ret < 0) -+ dev_err(rpisense->dev, "Read from reg %d failed\n", reg); -+ /* Due to the BCM270x I2C clock stretching bug, some values -+ * may have MSB set. Clear it to avoid incorrect values. -+ * */ -+ return ret & 0x7F; -+} -+EXPORT_SYMBOL_GPL(rpisense_reg_read); -+ -+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count) -+{ -+ int ret = i2c_master_send(rpisense->i2c_client, buf, count); -+ -+ if (ret < 0) -+ dev_err(rpisense->dev, "Block write failed\n"); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(rpisense_block_write); -+ -+static const struct i2c_device_id rpisense_i2c_id[] = { -+ { "rpi-sense", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id); -+ -+#ifdef CONFIG_OF -+static const struct of_device_id rpisense_core_id[] = { -+ { .compatible = "rpi,rpi-sense" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, rpisense_core_id); -+#endif -+ -+ -+static struct i2c_driver rpisense_driver = { -+ .driver = { -+ .name = "rpi-sense", -+ .owner = THIS_MODULE, -+ }, -+ .probe = rpisense_probe, -+ .remove = rpisense_remove, -+ .id_table = rpisense_i2c_id, -+}; -+ -+module_i2c_driver(rpisense_driver); -+ -+MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver"); -+MODULE_AUTHOR("Serge Schneider "); -+MODULE_LICENSE("GPL"); -+ diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c -index 6eda79533208..7b98ee263967 100644 +index 6eda79533208..67f74304f2bf 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -29,6 +29,15 @@ static const struct regmap_config regmap_config_8r_8v = { @@ -137455,11 +152017,12 @@ index 6eda79533208..7b98ee263967 100644 static int simple_mfd_i2c_probe(struct i2c_client *i2c) { const struct simple_mfd_data *simple_mfd_data; -@@ -88,6 +97,7 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { +@@ -88,6 +97,8 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, { .compatible = "maxim,max5970", .data = &maxim_max5970}, { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "raspberrypi,poe-core", &rpi_poe_core }, ++ { .compatible = "raspberrypi,sensehat" }, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); @@ -138454,7 +153017,7 @@ index 000000000000..acb54c2224cd +MODULE_DESCRIPTION("Device driver for BCM2835's secondary memory interface"); +MODULE_AUTHOR("Luke Wren "); diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c -index 3564a0f63c9c..a5794d2ee6ce 100644 +index 3564a0f63c9c..d5aca7b6dac7 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -171,6 +171,13 @@ static DEFINE_MUTEX(open_lock); @@ -138525,7 +153088,63 @@ index 3564a0f63c9c..a5794d2ee6ce 100644 break; case MMC_DRV_OP_BOOT_WP: ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, -@@ -1942,7 +1963,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) +@@ -1156,12 +1177,26 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, + unsigned int from, nr; + int err = 0; + blk_status_t status = BLK_STS_OK; ++ bool restart_cmdq = false; + + if (!mmc_can_erase(card)) { + status = BLK_STS_NOTSUPP; + goto fail; + } + ++ /* ++ * Only Discard ops are supported with SD cards in CQ mode ++ * (SD Physical Spec v9.00 4.19.2) ++ */ ++ if (mmc_card_sd(card) && card->ext_csd.cmdq_en && erase_arg != SD_DISCARD_ARG) { ++ restart_cmdq = true; ++ err = mmc_sd_cmdq_disable(card); ++ if (err) { ++ status = BLK_STS_IOERR; ++ goto fail; ++ } ++ } ++ + from = blk_rq_pos(req); + nr = blk_rq_sectors(req); + +@@ -1182,6 +1217,11 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, + status = BLK_STS_IOERR; + else + mmc_blk_reset_success(md, type); ++ ++ if (restart_cmdq) ++ err = mmc_sd_cmdq_enable(card); ++ if (err) ++ status = BLK_STS_IOERR; + fail: + blk_mq_end_request(req, status); + } +@@ -1503,6 +1543,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) + struct request_queue *q = req->q; + struct mmc_host *host = mq->card->host; + enum mmc_issue_type issue_type = mmc_issue_type(mq, req); ++ bool write = req_op(req) == REQ_OP_WRITE; + unsigned long flags; + bool put_card; + int err; +@@ -1534,6 +1575,8 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) + + spin_lock_irqsave(&mq->lock, flags); + ++ if (write) ++ mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + + put_card = (mmc_tot_in_flight(mq) == 0); +@@ -1942,7 +1985,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) return; } @@ -138534,7 +153153,52 @@ index 3564a0f63c9c..a5794d2ee6ce 100644 queue_physical_block_size(mq->queue) >> 9) { /* Read one (native) sector at a time */ mmc_blk_read_single(mq, req); -@@ -3008,6 +3029,8 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -2050,6 +2093,8 @@ static void mmc_blk_mq_complete_rq(struct mmc_queue *mq, struct request *req) + struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); + unsigned int nr_bytes = mqrq->brq.data.bytes_xfered; + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + if (nr_bytes) { + if (blk_update_request(req, BLK_STS_OK, nr_bytes)) + blk_mq_requeue_request(req, true); +@@ -2144,13 +2189,17 @@ static void mmc_blk_mq_poll_completion(struct mmc_queue *mq, + mmc_blk_urgent_bkops(mq, mqrq); + } + +-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type) ++static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type, ++ bool write) + { + unsigned long flags; + bool put_card; + + spin_lock_irqsave(&mq->lock, flags); + ++ if (write) ++ mq->pending_writes--; ++ + mq->in_flight[issue_type] -= 1; + + put_card = (mmc_tot_in_flight(mq) == 0); +@@ -2165,6 +2214,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req, + bool can_sleep) + { + enum mmc_issue_type issue_type = mmc_issue_type(mq, req); ++ bool write = req_op(req) == REQ_OP_WRITE; + struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); + struct mmc_request *mrq = &mqrq->brq.mrq; + struct mmc_host *host = mq->card->host; +@@ -2184,7 +2234,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req, + blk_mq_complete_request(req); + } + +- mmc_blk_mq_dec_in_flight(mq, issue_type); ++ mmc_blk_mq_dec_in_flight(mq, issue_type, write); + } + + void mmc_blk_mq_recovery(struct mmc_queue *mq) +@@ -3008,6 +3058,8 @@ static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; int ret = 0; @@ -138543,7 +153207,7 @@ index 3564a0f63c9c..a5794d2ee6ce 100644 /* * Check that the card supports the command class(es) we need. -@@ -3015,7 +3038,16 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -3015,7 +3067,16 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; @@ -138561,7 +153225,7 @@ index 3564a0f63c9c..a5794d2ee6ce 100644 card->complete_wq = alloc_workqueue("mmc_complete", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); -@@ -3030,6 +3062,17 @@ static int mmc_blk_probe(struct mmc_card *card) +@@ -3030,6 +3091,17 @@ static int mmc_blk_probe(struct mmc_card *card) goto out_free; } @@ -138605,7 +153269,7 @@ index b7754a1b8d97..c282b71668bd 100644 #define CID_MANFID_KINGSTON 0x70 #define CID_MANFID_HYNIX 0x90 diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c -index a8c17b4cd737..0d59beadecb8 100644 +index a8c17b4cd737..d5e9c55a9e6c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -455,6 +455,7 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) @@ -138616,7 +153280,27 @@ index a8c17b4cd737..0d59beadecb8 100644 return 0; -@@ -556,7 +557,11 @@ int mmc_cqe_recovery(struct mmc_host *host) +@@ -542,10 +543,18 @@ int mmc_cqe_recovery(struct mmc_host *host) + * Recovery is expected seldom, if at all, but it reduces performance, + * so make sure it is not completely silent. + */ +- pr_warn("%s: running CQE recovery\n", mmc_hostname(host)); ++ pr_warn_ratelimited("%s: running CQE recovery\n", mmc_hostname(host)); + + host->cqe_ops->cqe_recovery_start(host); + ++ err = mmc_detect_card_removed(host); ++ if (err) { ++ host->cqe_ops->cqe_recovery_finish(host); ++ host->cqe_ops->cqe_off(host); ++ mmc_retune_release(host); ++ return err; ++ } ++ + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = MMC_STOP_TRANSMISSION; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; +@@ -556,7 +565,11 @@ int mmc_cqe_recovery(struct mmc_host *host) mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO); memset(&cmd, 0, sizeof(cmd)); @@ -138629,7 +153313,7 @@ index a8c17b4cd737..0d59beadecb8 100644 cmd.arg = 1; /* Discard entire queue */ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */ -@@ -1818,7 +1823,8 @@ EXPORT_SYMBOL(mmc_erase); +@@ -1818,7 +1831,8 @@ EXPORT_SYMBOL(mmc_erase); int mmc_can_erase(struct mmc_card *card) { @@ -138640,10 +153324,18 @@ index a8c17b4cd737..0d59beadecb8 100644 return 0; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c -index 3a927452a650..450683646196 100644 +index 7e39017e440f..8f1baf4a5430 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c -@@ -1910,8 +1910,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, +@@ -1663,6 +1663,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, + card->ocr = ocr; + card->type = MMC_TYPE_MMC; + card->rca = 1; ++ card->max_posted_writes = 1; + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + } + +@@ -1915,13 +1916,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, host->cqe_enabled = true; if (card->ext_csd.cmdq_en) { @@ -138654,24 +153346,66 @@ index 3a927452a650..450683646196 100644 } else { host->hsq_enabled = true; pr_info("%s: Host Software Queue enabled\n", + mmc_hostname(host)); + } ++ card->max_posted_writes = card->ext_csd.cmdq_depth; + } + } + +diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c +index b396e3900717..c73ac1125efa 100644 +--- a/drivers/mmc/core/queue.c ++++ b/drivers/mmc/core/queue.c +@@ -268,6 +268,11 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, + spin_unlock_irq(&mq->lock); + return BLK_STS_RESOURCE; + } ++ if (!host->hsq_enabled && host->cqe_enabled && req_op(req) == REQ_OP_WRITE && ++ mq->pending_writes >= card->max_posted_writes) { ++ spin_unlock_irq(&mq->lock); ++ return BLK_STS_RESOURCE; ++ } + break; + default: + /* +@@ -284,6 +289,8 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, + /* Parallel dispatch of requests is not supported at the moment */ + mq->busy = true; + ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes++; + mq->in_flight[issue_type] += 1; + get_card = (mmc_tot_in_flight(mq) == 1); + cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1); +@@ -323,6 +330,8 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, + bool put_card = false; + + spin_lock_irq(&mq->lock); ++ if (req_op(req) == REQ_OP_WRITE) ++ mq->pending_writes--; + mq->in_flight[issue_type] -= 1; + if (mmc_tot_in_flight(mq) == 0) + put_card = true; +diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h +index 9ade3bcbb714..7610cc759910 100644 +--- a/drivers/mmc/core/queue.h ++++ b/drivers/mmc/core/queue.h +@@ -79,6 +79,7 @@ struct mmc_queue { + struct request_queue *queue; + spinlock_t lock; + int in_flight[MMC_ISSUE_MAX]; ++ int pending_writes; + unsigned int cqe_busy; + #define MMC_CQE_DCMD_BUSY BIT(0) + bool busy; diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h -index cca71867bc4a..ddefedc9746e 100644 +index 92905fc46436..2c6921e6f6dd 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h -@@ -15,6 +15,27 @@ +@@ -25,6 +25,26 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = { + 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, + MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), - #include "card.h" - -+static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = { -+ /* -+ * Kingston Canvas Go! Plus microSD cards never finish SD cache flush. -+ * This has so far only been observed on cards from 11/2019, while new -+ * cards from 2023/05 do not exhibit this behavior. -+ */ -+ _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11, -+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, -+ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), -+ + /* + * Samsung Pro Plus/EVO Plus/Pro Ultimate SD cards (2023) claim to cache + * flush OK, but become unresponsive afterwards. @@ -138680,29 +153414,22 @@ index cca71867bc4a..ddefedc9746e 100644 + 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, + MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), + -+ END_FIXUP -+}; ++ /* ++ * Early Sandisk Extreme and Extreme Pro A2 cards never finish SD cache ++ * flush in CQ mode. Latest card date this was seen on is 10/2020. ++ */ ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2019, CID_MONTH_ANY, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), + - static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { - #define INAND_CMD38_ARG_EXT_CSD 113 - #define INAND_CMD38_ARG_ERASE 0x00 -@@ -53,15 +74,6 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { - MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, 2020, CID_MONTH_ANY, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), ++ + END_FIXUP + }; -- /* -- * Kingston Canvas Go! Plus microSD cards never finish SD cache flush. -- * This has so far only been observed on cards from 11/2019, while new -- * cards from 2023/05 do not exhibit this behavior. -- */ -- _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11, -- 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, -- MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), -- - /* - * Some SD cards lockup while using CMD23 multiblock transfers. - */ -@@ -130,6 +142,14 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { +@@ -134,6 +154,23 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd, MMC_QUIRK_BROKEN_SD_DISCARD), @@ -138713,23 +153440,24 @@ index cca71867bc4a..ddefedc9746e 100644 + MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), + MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), + MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ ++ /* ++ * Larger Integral SD cards using rebranded Phison controllers trash ++ * nearby flash blocks after erases. ++ */ ++ MMC_FIXUP("SD64G", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD128", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD256", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), ++ MMC_FIXUP("SD512", 0x27, 0x5048, add_quirk, MMC_QUIRK_ERASE_BROKEN), + END_FIXUP }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index c3e554344c99..bd0e14714e39 100644 +index 240469a881a2..b1ea31d98442 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c -@@ -26,6 +26,7 @@ - #include "host.h" - #include "bus.h" - #include "mmc_ops.h" -+#include "quirks.h" - #include "sd.h" - #include "sd_ops.h" - -@@ -714,7 +715,8 @@ MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); +@@ -715,7 +715,8 @@ MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); @@ -138739,7 +153467,7 @@ index c3e554344c99..bd0e14714e39 100644 static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr, char *buf) -@@ -776,6 +778,8 @@ static struct attribute *sd_std_attrs[] = { +@@ -777,6 +778,8 @@ static struct attribute *sd_std_attrs[] = { &dev_attr_ocr.attr, &dev_attr_rca.attr, &dev_attr_dsr.attr, @@ -138748,7 +153476,7 @@ index c3e554344c99..bd0e14714e39 100644 NULL, }; -@@ -1015,98 +1019,16 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card) +@@ -1016,98 +1019,16 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card) (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50); } @@ -138849,7 +153577,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) { pr_warn("%s: error %d reading PM func of ext reg\n", mmc_hostname(card->host), err); -@@ -1133,7 +1055,6 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page, +@@ -1134,7 +1055,6 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page, card->ext_power.offset = offset; out: @@ -138857,7 +153585,7 @@ index c3e554344c99..bd0e14714e39 100644 return err; } -@@ -1143,11 +1064,9 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, +@@ -1144,11 +1064,9 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, int err; u8 *reg_buf; @@ -138871,7 +153599,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) { pr_warn("%s: error %d reading PERF func of ext reg\n", mmc_hostname(card->host), err); -@@ -1173,16 +1092,25 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, +@@ -1174,16 +1092,34 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, if ((reg_buf[4] & BIT(0)) && !mmc_card_broken_sd_cache(card)) card->ext_perf.feature_support |= SD_EXT_PERF_CACHE; @@ -138889,6 +153617,15 @@ index c3e554344c99..bd0e14714e39 100644 + pr_debug("%s: Command Queue supported depth %u\n", + mmc_hostname(card->host), + card->ext_csd.cmdq_depth); ++ /* ++ * If CQ is enabled, there is a contract between host and card such that ++ * VDD will be maintained and removed only if a power off notification ++ * is provided. An SD card in an accessible slot means surprise removal ++ * is a possibility. As a middle ground, keep the default maximum of 1 ++ * posted write unless the card is "hardwired". ++ */ ++ if (!mmc_card_is_removable(card->host)) ++ card->max_posted_writes = card->ext_csd.cmdq_depth; + } card->ext_perf.fno = fno; @@ -138900,7 +153637,7 @@ index c3e554344c99..bd0e14714e39 100644 return err; } -@@ -1237,7 +1165,7 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf, +@@ -1238,7 +1174,7 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf, return 0; } @@ -138909,7 +153646,7 @@ index c3e554344c99..bd0e14714e39 100644 { int err, i; u8 num_ext, *gen_info_buf; -@@ -1249,15 +1177,21 @@ static int sd_read_ext_regs(struct mmc_card *card) +@@ -1250,15 +1186,21 @@ static int sd_read_ext_regs(struct mmc_card *card) if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT)) return 0; @@ -138933,7 +153670,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) { pr_err("%s: error %d reading general info of SD ext reg\n", mmc_hostname(card->host), err); -@@ -1274,14 +1208,23 @@ static int sd_read_ext_regs(struct mmc_card *card) +@@ -1275,14 +1217,23 @@ static int sd_read_ext_regs(struct mmc_card *card) num_ext = gen_info_buf[4]; /* @@ -138961,7 +153698,7 @@ index c3e554344c99..bd0e14714e39 100644 goto out; } -@@ -1319,9 +1262,7 @@ static int sd_flush_cache(struct mmc_host *host) +@@ -1320,9 +1271,7 @@ static int sd_flush_cache(struct mmc_host *host) if (!sd_cache_enabled(host)) return 0; @@ -138972,7 +153709,7 @@ index c3e554344c99..bd0e14714e39 100644 /* * Set Flush Cache at bit 0 in the performance enhancement register at -@@ -1331,7 +1272,7 @@ static int sd_flush_cache(struct mmc_host *host) +@@ -1332,7 +1281,7 @@ static int sd_flush_cache(struct mmc_host *host) page = card->ext_perf.page; offset = card->ext_perf.offset + 261; @@ -138981,7 +153718,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) { pr_warn("%s: error %d writing Cache Flush bit\n", mmc_hostname(host), err); -@@ -1347,7 +1288,7 @@ static int sd_flush_cache(struct mmc_host *host) +@@ -1348,7 +1297,7 @@ static int sd_flush_cache(struct mmc_host *host) * Read the Flush Cache bit. The card shall reset it, to confirm that * it's has completed the flushing of the cache. */ @@ -138990,7 +153727,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) { pr_warn("%s: error %d reading Cache Flush bit\n", mmc_hostname(host), err); -@@ -1357,26 +1298,20 @@ static int sd_flush_cache(struct mmc_host *host) +@@ -1358,26 +1307,20 @@ static int sd_flush_cache(struct mmc_host *host) if (reg_buf[0] & BIT(0)) err = -ETIMEDOUT; out: @@ -139018,7 +153755,7 @@ index c3e554344c99..bd0e14714e39 100644 card->ext_perf.offset + 260, BIT(0)); if (err) { pr_warn("%s: error %d writing Cache Enable bit\n", -@@ -1390,7 +1325,6 @@ static int sd_enable_cache(struct mmc_card *card) +@@ -1391,7 +1334,6 @@ static int sd_enable_cache(struct mmc_card *card) card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE; out: @@ -139026,17 +153763,15 @@ index c3e554344c99..bd0e14714e39 100644 return err; } -@@ -1475,6 +1409,9 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, - goto free_card; +@@ -1434,6 +1376,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, + + card->ocr = ocr; + card->type = MMC_TYPE_SD; ++ card->max_posted_writes = 1; + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); } -+ /* Apply quirks prior to card setup */ -+ mmc_fixup_device(card, mmc_sd_fixups); -+ - err = mmc_sd_setup_card(host, card, oldcard != NULL); - if (err) - goto free_card; -@@ -1547,7 +1484,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, +@@ -1551,7 +1494,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, cont: if (!oldcard) { /* Read/parse the extension registers. */ @@ -139045,7 +153780,7 @@ index c3e554344c99..bd0e14714e39 100644 if (err) goto free_card; } -@@ -1559,13 +1496,41 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, +@@ -1563,13 +1506,41 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; } @@ -139090,7 +153825,7 @@ index c3e554344c99..bd0e14714e39 100644 } } -@@ -1646,7 +1611,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy) +@@ -1650,7 +1621,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy) * one byte offset and is one byte long. The Power Off Notification * Ready is bit 0. */ @@ -139099,7 +153834,7 @@ index c3e554344c99..bd0e14714e39 100644 card->ext_power.offset + 1, 1, data->reg_buf); if (err) { pr_warn("%s: error %d reading status reg of PM func\n", -@@ -1672,7 +1637,7 @@ static int sd_poweroff_notify(struct mmc_card *card) +@@ -1676,7 +1647,7 @@ static int sd_poweroff_notify(struct mmc_card *card) * Set the Power Off Notification bit in the power management settings * register at 2 bytes offset. */ @@ -143189,7 +157924,7 @@ index 35d8fdea668b..746a60fac0f0 100644 host->dma_chan = NULL; host->dma_desc = NULL; diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c -index 41e94cd14109..5da5bf8ad038 100644 +index fe7a4eac9595..5da5bf8ad038 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -383,9 +383,11 @@ static void cqhci_off(struct mmc_host *mmc) @@ -143206,15 +157941,6 @@ index 41e94cd14109..5da5bf8ad038 100644 pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc)); if (cq_host->ops->post_disable) -@@ -612,7 +614,7 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) - cqhci_writel(cq_host, 0, CQHCI_CTL); - mmc->cqe_on = true; - pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc)); -- if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) { -+ if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) { - pr_err("%s: cqhci: CQE failed to exit halt state\n", - mmc_hostname(mmc)); - } @@ -975,8 +977,11 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout) ret = cqhci_halted(cq_host); @@ -143229,7 +157955,7 @@ index 41e94cd14109..5da5bf8ad038 100644 return ret; } diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c -index c23251bb95f3..61cea31cc891 100644 +index 25664cd5e90f..143226c2afc2 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -11,6 +11,8 @@ @@ -143241,7 +157967,7 @@ index c23251bb95f3..61cea31cc891 100644 #include "sdhci-cqhci.h" #include "sdhci-pltfm.h" -@@ -26,18 +28,43 @@ +@@ -27,18 +29,43 @@ #define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0) #define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1) @@ -143285,7 +158011,7 @@ index c23251bb95f3..61cea31cc891 100644 struct sdhci_ops *ops; const unsigned int flags; }; -@@ -79,6 +106,42 @@ static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios) +@@ -80,6 +107,42 @@ static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios) writel(reg, host->ioaddr + SDHCI_VENDOR); } @@ -143328,7 +158054,7 @@ index c23251bb95f3..61cea31cc891 100644 static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; -@@ -94,6 +157,17 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) +@@ -95,6 +158,17 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_enable_clk(host, clk); } @@ -143346,10 +158072,24 @@ index c23251bb95f3..61cea31cc891 100644 static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { -@@ -123,6 +197,139 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, +@@ -124,6 +198,155 @@ static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host, sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } ++static void sdhci_bcm2712_hs400_downgrade(struct mmc_host *mmc) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ /* ++ * The eMMC PHY and its internal controller parses and validates ++ * the uhs_mode, divisor, pin_sel, and sampling clock select ++ * output from the SD controller. It will refuse to update its ++ * config if HS timings are selected while the clock is >52MHz. ++ * so bump the clock down now before card/controller setup is ++ * performed. ++ */ ++ sdhci_bcm2712_set_clock(host, 52000000); ++} ++ +static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -143368,6 +158108,8 @@ index c23251bb95f3..61cea31cc891 100644 + reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE; + reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE; + writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); ++ ++ host->mmc_host_ops.hs400_downgrade = sdhci_bcm2712_hs400_downgrade; + } + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || @@ -143486,7 +158228,7 @@ index c23251bb95f3..61cea31cc891 100644 static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) { sdhci_dumpregs(mmc_priv(mmc)); -@@ -131,6 +338,7 @@ static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) +@@ -132,6 +355,7 @@ static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc) static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -143494,17 +158236,30 @@ index c23251bb95f3..61cea31cc891 100644 u32 reg; reg = sdhci_readl(host, SDHCI_PRESENT_STATE); -@@ -140,6 +348,9 @@ static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc) +@@ -141,6 +365,22 @@ static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc) } sdhci_cqe_enable(mmc); + -+ /* Reset CMD13 polling timer back to eMMC specification default */ -+ cqhci_writel(cq_host, 0x00011000, CQHCI_SSC1); ++ /* ++ * The controller resets this register to a very short default interval ++ * whenever CQHCI is disabled. ++ * ++ * For removable cards CBC needs to be clear or card removal can hang ++ * the CQE. In polling mode, a CIT of 0x4000 "cycles" seems to produce the best ++ * throughput. ++ * ++ * For nonremovable cards, the specification default of CBC=1 CIT=0x1000 ++ * suffices. ++ */ ++ if (mmc->caps & MMC_CAP_NONREMOVABLE) ++ cqhci_writel(cq_host, 0x00011000, CQHCI_SSC1); ++ else ++ cqhci_writel(cq_host, 0x00004000, CQHCI_SSC1); } static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = { -@@ -155,6 +366,15 @@ static struct sdhci_ops sdhci_brcmstb_ops = { +@@ -156,6 +396,15 @@ static struct sdhci_ops sdhci_brcmstb_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; @@ -143512,7 +158267,7 @@ index c23251bb95f3..61cea31cc891 100644 + .set_clock = sdhci_bcm2712_set_clock, + .set_power = sdhci_brcmstb_set_power, + .set_bus_width = sdhci_set_bus_width, -+ .reset = sdhci_reset, ++ .reset = brcmstb_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .init_sd_express = bcm2712_init_sd_express, +}; @@ -143520,12 +158275,12 @@ index c23251bb95f3..61cea31cc891 100644 static struct sdhci_ops sdhci_brcmstb_ops_7216 = { .set_clock = sdhci_brcmstb_set_clock, .set_bus_width = sdhci_set_bus_width, -@@ -179,10 +399,18 @@ static const struct brcmstb_match_priv match_priv_7216 = { +@@ -180,10 +429,18 @@ static const struct brcmstb_match_priv match_priv_7216 = { .ops = &sdhci_brcmstb_ops_7216, }; +static const struct brcmstb_match_priv match_priv_2712 = { -+ .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, ++ .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY, + .hs400es = sdhci_brcmstb_hs400es, + .cfginit = sdhci_brcmstb_cfginit_2712, + .ops = &sdhci_brcmstb_ops_2712, @@ -143539,7 +158294,7 @@ index c23251bb95f3..61cea31cc891 100644 {}, }; -@@ -255,6 +483,8 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) +@@ -256,6 +513,8 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) struct sdhci_brcmstb_priv *priv; u32 actual_clock_mhz; struct sdhci_host *host; @@ -143548,7 +158303,7 @@ index c23251bb95f3..61cea31cc891 100644 struct clk *clk; struct clk *base_clk = NULL; int res; -@@ -277,12 +507,19 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) +@@ -278,12 +537,19 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) return PTR_ERR(host); pltfm_host = sdhci_priv(host); @@ -143568,7 +158323,7 @@ index c23251bb95f3..61cea31cc891 100644 /* Map in the non-standard CFG registers */ priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); if (IS_ERR(priv->cfg_regs)) { -@@ -295,6 +532,43 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) +@@ -296,6 +562,43 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) if (res) goto err; @@ -143612,7 +158367,7 @@ index c23251bb95f3..61cea31cc891 100644 /* * Automatic clock gating does not work for SD cards that may * voltage switch so only enable it for non-removable devices. -@@ -311,6 +585,13 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) +@@ -312,6 +615,13 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) (host->mmc->caps2 & MMC_CAP2_HS400_ES)) host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es; @@ -143626,7 +158381,7 @@ index c23251bb95f3..61cea31cc891 100644 /* * Supply the existing CAPS, but clear the UHS modes. This * will allow these modes to be specified by device tree -@@ -358,7 +639,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) +@@ -362,7 +672,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) if (res) goto err; @@ -143821,7 +158576,7 @@ index b81d5b0fd616..4eb77191c421 100644 { return host->private; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index ff41aa56564e..7e9ec325b87c 100644 +index 9796a3cb3ca6..75ebf333330b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -40,7 +40,7 @@ @@ -143833,6 +158588,15 @@ index ff41aa56564e..7e9ec325b87c 100644 #define MAX_TUNING_LOOP 40 +@@ -1081,7 +1081,7 @@ static void sdhci_initialize_data(struct sdhci_host *host, + WARN_ON(host->data); + + /* Sanity checks */ +- BUG_ON(data->blksz * data->blocks > 524288); ++ BUG_ON(data->blksz * data->blocks > host->mmc->max_req_size); + BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > 65535); + @@ -1713,6 +1713,12 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (host->use_external_dma) sdhci_external_dma_pre_transfer(host, cmd); @@ -143846,7 +158610,7 @@ index ff41aa56564e..7e9ec325b87c 100644 sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); return true; -@@ -3047,6 +3053,15 @@ static void sdhci_card_event(struct mmc_host *mmc) +@@ -3050,6 +3056,15 @@ static void sdhci_card_event(struct mmc_host *mmc) spin_unlock_irqrestore(&host->lock, flags); } @@ -143862,7 +158626,7 @@ index ff41aa56564e..7e9ec325b87c 100644 static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .post_req = sdhci_post_req, -@@ -3062,6 +3077,7 @@ static const struct mmc_host_ops sdhci_ops = { +@@ -3065,6 +3080,7 @@ static const struct mmc_host_ops sdhci_ops = { .execute_tuning = sdhci_execute_tuning, .card_event = sdhci_card_event, .card_busy = sdhci_card_busy, @@ -143870,7 +158634,7 @@ index ff41aa56564e..7e9ec325b87c 100644 }; /*****************************************************************************\ -@@ -3209,7 +3225,7 @@ static void sdhci_timeout_timer(struct timer_list *t) +@@ -3212,7 +3228,7 @@ static void sdhci_timeout_timer(struct timer_list *t) spin_lock_irqsave(&host->lock, flags); if (host->cmd && !sdhci_data_line_cmd(host->cmd)) { @@ -143879,7 +158643,7 @@ index ff41aa56564e..7e9ec325b87c 100644 mmc_hostname(host->mmc)); sdhci_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); -@@ -3232,7 +3248,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) +@@ -3235,7 +3251,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) if (host->data || host->data_cmd || (host->cmd && sdhci_data_line_cmd(host->cmd))) { @@ -143888,7 +158652,7 @@ index ff41aa56564e..7e9ec325b87c 100644 mmc_hostname(host->mmc)); sdhci_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); -@@ -3296,6 +3312,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) +@@ -3299,6 +3315,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) if (intmask & SDHCI_INT_TIMEOUT) { host->cmd->error = -ETIMEDOUT; sdhci_err_stats_inc(host, CMD_TIMEOUT); @@ -143900,7 +158664,7 @@ index ff41aa56564e..7e9ec325b87c 100644 } else { host->cmd->error = -EILSEQ; if (!mmc_op_tuning(host->cmd->opcode)) -@@ -4574,6 +4595,15 @@ int sdhci_setup_host(struct sdhci_host *host) +@@ -4583,6 +4604,15 @@ int sdhci_setup_host(struct sdhci_host *host) !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) mmc->caps |= MMC_CAP_UHS_DDR50; @@ -143916,11 +158680,32 @@ index ff41aa56564e..7e9ec325b87c 100644 /* Does the host need tuning for SDR50? */ if (host->caps1 & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; +@@ -4697,11 +4727,16 @@ int sdhci_setup_host(struct sdhci_host *host) + spin_lock_init(&host->lock); + + /* +- * Maximum number of sectors in one transfer. Limited by SDMA boundary +- * size (512KiB). Note some tuning modes impose a 4MiB limit, but this +- * is less anyway. ++ * Maximum number of sectors in one transfer. ++ * 4MiB is preferred for multi-descriptor DMA as a) card sequential ++ * write speeds are only guaranteed with a 4MiB write length and ++ * b) most tuning modes require a 4MiB limit. ++ * SDMA has a 512KiB boundary size. + */ +- mmc->max_req_size = 524288; ++ if (host->flags & SDHCI_USE_ADMA) ++ mmc->max_req_size = SZ_4M; ++ else ++ mmc->max_req_size = SZ_512K; + + /* + * Maximum number of segments. Depends on if the hardware diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h -index f219bdea8f28..112402286f73 100644 +index a315cee69809..45121666b87d 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h -@@ -486,6 +486,14 @@ struct sdhci_host { +@@ -487,6 +487,14 @@ struct sdhci_host { /* Issue CMD and DATA reset together */ #define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) @@ -143935,7 +158720,7 @@ index f219bdea8f28..112402286f73 100644 int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ phys_addr_t mapbase; /* physical address base */ -@@ -668,6 +676,7 @@ struct sdhci_ops { +@@ -669,6 +677,7 @@ struct sdhci_ops { void (*request_done)(struct sdhci_host *host, struct mmc_request *mrq); void (*dump_vendor_regs)(struct sdhci_host *host); @@ -143944,7 +158729,7 @@ index f219bdea8f28..112402286f73 100644 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -index 89c8ddc6565a..0ca1dcc04002 100644 +index 79d096a371ae..0b7764c4ab84 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -67,6 +67,12 @@ @@ -143960,7 +158745,7 @@ index 89c8ddc6565a..0ca1dcc04002 100644 static inline void bcmgenet_writel(u32 value, void __iomem *offset) { -@@ -2491,6 +2497,11 @@ static void reset_umac(struct bcmgenet_priv *priv) +@@ -2495,6 +2501,11 @@ static void reset_umac(struct bcmgenet_priv *priv) bcmgenet_rbuf_ctrl_set(priv, 0); udelay(10); @@ -143970,9 +158755,9 @@ index 89c8ddc6565a..0ca1dcc04002 100644 + } + /* issue soft reset and disable MAC while updating its registers */ + spin_lock_bh(&priv->reg_lock); bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD); - udelay(2); -@@ -2660,7 +2671,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, +@@ -2666,7 +2677,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); @@ -143981,42 +158766,7 @@ index 89c8ddc6565a..0ca1dcc04002 100644 /* Disable rate control for now */ bcmgenet_tdma_ring_writel(priv, index, flow_period_val, TDMA_FLOW_PERIOD); -@@ -3299,7 +3310,7 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, - } - - /* Returns a reusable dma control register value */ --static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) -+static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) - { - unsigned int i; - u32 reg; -@@ -3324,6 +3335,14 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) - udelay(10); - bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH); - -+ if (flush_rx) { -+ reg = bcmgenet_rbuf_ctrl_get(priv); -+ bcmgenet_rbuf_ctrl_set(priv, reg | BIT(0)); -+ udelay(10); -+ bcmgenet_rbuf_ctrl_set(priv, reg); -+ udelay(10); -+ } -+ - return dma_ctrl; - } - -@@ -3387,8 +3406,8 @@ static int bcmgenet_open(struct net_device *dev) - - bcmgenet_set_hw_addr(priv, dev->dev_addr); - -- /* Disable RX/TX DMA and flush TX queues */ -- dma_ctrl = bcmgenet_dma_disable(priv); -+ /* Disable RX/TX DMA and flush TX and RX queues */ -+ dma_ctrl = bcmgenet_dma_disable(priv, true); - - /* Reinitialize TDMA and RDMA and SW housekeeping */ - ret = bcmgenet_init_dma(priv); -@@ -3425,6 +3444,17 @@ static int bcmgenet_open(struct net_device *dev) +@@ -3441,6 +3452,17 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause); @@ -144034,7 +158784,7 @@ index 89c8ddc6565a..0ca1dcc04002 100644 bcmgenet_netif_start(dev); netif_tx_start_all_queues(dev); -@@ -4141,9 +4171,12 @@ static int bcmgenet_probe(struct platform_device *pdev) +@@ -4161,9 +4183,12 @@ static int bcmgenet_probe(struct platform_device *pdev) netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); /* Set default coalescing parameters */ @@ -144048,17 +158798,8 @@ index 89c8ddc6565a..0ca1dcc04002 100644 /* libphy will determine the link state */ netif_carrier_off(dev); -@@ -4259,7 +4292,7 @@ static int bcmgenet_resume(struct device *d) - bcmgenet_hfb_create_rxnfc_filter(priv, rule); - - /* Disable RX/TX DMA and flush TX queues */ -- dma_ctrl = bcmgenet_dma_disable(priv); -+ dma_ctrl = bcmgenet_dma_disable(priv, false); - - /* Reinitialize TDMA and RDMA and SW housekeeping */ - ret = bcmgenet_init_dma(priv); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h -index 1985c0ec4da2..4a73c1572398 100644 +index 28e2c94ef835..44e42d7d2689 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -31,7 +31,7 @@ @@ -144071,10 +158812,10 @@ index 1985c0ec4da2..4a73c1572398 100644 /* misc. configuration */ #define MAX_NUM_OF_FS_RULES 16 diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c -index 97ea76d443ab..7f856f5a26d6 100644 +index e7c659cd3974..7a906edbb3f7 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c -@@ -299,14 +299,14 @@ int bcmgenet_mii_probe(struct net_device *dev) +@@ -303,14 +303,14 @@ int bcmgenet_mii_probe(struct net_device *dev) struct device_node *dn = kdev->of_node; phy_interface_t phy_iface = priv->phy_interface; struct phy_device *phydev; @@ -144160,7 +158901,7 @@ index 78c972bb1d96..2e259d91b936 100644 struct macb_tx_skb rm9200_txq[2]; unsigned int max_tx_length; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c -index b940dcd3ace6..79fab300a534 100644 +index 8f61731e4554..0f9080371c4e 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -40,6 +40,9 @@ @@ -144202,7 +158943,7 @@ index b940dcd3ace6..79fab300a534 100644 static void macb_init_buffers(struct macb *bp) { struct macb_queue *queue; -@@ -969,6 +985,7 @@ static int macb_mii_init(struct macb *bp) +@@ -977,6 +993,7 @@ static int macb_mii_init(struct macb *bp) bp->mii_bus->write = &macb_mdio_write_c22; bp->mii_bus->read_c45 = &macb_mdio_read_c45; bp->mii_bus->write_c45 = &macb_mdio_write_c45; @@ -144210,7 +158951,7 @@ index b940dcd3ace6..79fab300a534 100644 snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", bp->pdev->name, bp->pdev->id); bp->mii_bus->priv = bp; -@@ -1640,6 +1657,11 @@ static int macb_rx(struct macb_queue *queue, struct napi_struct *napi, +@@ -1648,6 +1665,11 @@ static int macb_rx(struct macb_queue *queue, struct napi_struct *napi, macb_init_rx_ring(queue); queue_writel(queue, RBQP, queue->rx_ring_dma); @@ -144222,7 +158963,7 @@ index b940dcd3ace6..79fab300a534 100644 macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); -@@ -1940,8 +1962,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) +@@ -1948,8 +1970,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) queue_writel(queue, ISR, MACB_BIT(TCOMP) | MACB_BIT(TXUBR)); @@ -144233,7 +158974,7 @@ index b940dcd3ace6..79fab300a534 100644 wmb(); // ensure softirq can see update } -@@ -2394,6 +2417,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) +@@ -2402,6 +2425,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); spin_lock_irq(&bp->lock); @@ -144245,7 +158986,7 @@ index b940dcd3ace6..79fab300a534 100644 macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); spin_unlock_irq(&bp->lock); -@@ -2768,6 +2796,37 @@ static void macb_configure_dma(struct macb *bp) +@@ -2776,6 +2804,37 @@ static void macb_configure_dma(struct macb *bp) } } @@ -144283,7 +159024,7 @@ index b940dcd3ace6..79fab300a534 100644 static void macb_init_hw(struct macb *bp) { u32 config; -@@ -2796,6 +2855,11 @@ static void macb_init_hw(struct macb *bp) +@@ -2804,6 +2863,11 @@ static void macb_init_hw(struct macb *bp) if (bp->caps & MACB_CAPS_JUMBO) bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; @@ -144295,7 +159036,7 @@ index b940dcd3ace6..79fab300a534 100644 macb_configure_dma(bp); /* Enable RX partial store and forward and set watermark */ -@@ -3157,6 +3221,52 @@ static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) +@@ -3165,6 +3229,52 @@ static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) } } @@ -144348,7 +159089,7 @@ index b940dcd3ace6..79fab300a534 100644 static struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); -@@ -3749,6 +3859,8 @@ static const struct ethtool_ops macb_ethtool_ops = { +@@ -3757,6 +3867,8 @@ static const struct ethtool_ops macb_ethtool_ops = { }; static const struct ethtool_ops gem_ethtool_ops = { @@ -144357,7 +159098,7 @@ index b940dcd3ace6..79fab300a534 100644 .get_regs_len = macb_get_regs_len, .get_regs = macb_get_regs, .get_wol = macb_get_wol, -@@ -3758,6 +3870,8 @@ static const struct ethtool_ops gem_ethtool_ops = { +@@ -3766,6 +3878,8 @@ static const struct ethtool_ops gem_ethtool_ops = { .get_ethtool_stats = gem_get_ethtool_stats, .get_strings = gem_get_ethtool_strings, .get_sset_count = gem_get_sset_count, @@ -144366,7 +159107,7 @@ index b940dcd3ace6..79fab300a534 100644 .get_link_ksettings = macb_get_link_ksettings, .set_link_ksettings = macb_set_link_ksettings, .get_ringparam = macb_get_ringparam, -@@ -5054,6 +5168,11 @@ static int macb_probe(struct platform_device *pdev) +@@ -5062,6 +5176,11 @@ static int macb_probe(struct platform_device *pdev) } } } @@ -144378,7 +159119,7 @@ index b940dcd3ace6..79fab300a534 100644 spin_lock_init(&bp->lock); /* setup capabilities */ -@@ -5109,6 +5228,21 @@ static int macb_probe(struct platform_device *pdev) +@@ -5117,6 +5236,21 @@ static int macb_probe(struct platform_device *pdev) else bp->phy_interface = interface; @@ -144400,7 +159141,7 @@ index b940dcd3ace6..79fab300a534 100644 /* IP specific init */ err = init(pdev); if (err) -@@ -5185,6 +5319,19 @@ static int macb_remove(struct platform_device *pdev) +@@ -5193,6 +5327,19 @@ static int macb_remove(struct platform_device *pdev) return 0; } @@ -144420,7 +159161,7 @@ index b940dcd3ace6..79fab300a534 100644 static int __maybe_unused macb_suspend(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); -@@ -5399,6 +5546,7 @@ static const struct dev_pm_ops macb_pm_ops = { +@@ -5407,6 +5554,7 @@ static const struct dev_pm_ops macb_pm_ops = { static struct platform_driver macb_driver = { .probe = macb_probe, .remove = macb_remove, @@ -144626,7 +159367,7 @@ index 000000000000..007d077edcad + rtl8168_setup_ldev(leds + i, ndev, i); +} diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c -index e6f1da66c450..59f1f156d4ea 100644 +index 115adbce6c56..010f09d39679 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -289,6 +289,7 @@ enum rtl8168_8101_registers { @@ -144637,7 +159378,7 @@ index e6f1da66c450..59f1f156d4ea 100644 LED_FREQ = 0x1a, EEE_LED = 0x1b, ERIDR = 0x70, -@@ -620,6 +621,7 @@ struct rtl8169_private { +@@ -647,6 +648,7 @@ struct rtl8169_private { raw_spinlock_t config25_lock; raw_spinlock_t mac_ocp_lock; @@ -144645,7 +159386,7 @@ index e6f1da66c450..59f1f156d4ea 100644 raw_spinlock_t cfg9346_usage_lock; int cfg9346_usage_count; -@@ -792,6 +794,62 @@ static const struct rtl_cond name = { \ +@@ -819,6 +821,62 @@ static const struct rtl_cond name = { \ \ static bool name ## _check(struct rtl8169_private *tp) @@ -144708,7 +159449,7 @@ index e6f1da66c450..59f1f156d4ea 100644 static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) { /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ -@@ -5259,6 +5317,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +@@ -5283,6 +5341,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) raw_spin_lock_init(&tp->cfg9346_usage_lock); raw_spin_lock_init(&tp->config25_lock); raw_spin_lock_init(&tp->mac_ocp_lock); @@ -144716,7 +159457,7 @@ index e6f1da66c450..59f1f156d4ea 100644 dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, struct pcpu_sw_netstats); -@@ -5415,6 +5474,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +@@ -5439,6 +5498,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; @@ -145055,17 +159796,13 @@ index 921ae046f860..a7f24d6c0cae 100644 buf = kmalloc(maxp, GFP_KERNEL); if (!buf) { diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index 2fa46baa589e..44aefcb23930 100644 +index 8e82184be5e7..737a1734e451 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c -@@ -79,6 +79,18 @@ static bool turbo_mode = true; +@@ -79,6 +79,14 @@ static bool turbo_mode = true; module_param(turbo_mode, bool, 0644); MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); -+static bool truesize_mode = false; -+module_param(truesize_mode, bool, 0644); -+MODULE_PARM_DESC(truesize_mode, "Report larger truesize value"); -+ +static int packetsize = 2560; +module_param(packetsize, int, 0644); +MODULE_PARM_DESC(packetsize, "Override the RX URB packet size"); @@ -145077,7 +159814,7 @@ index 2fa46baa589e..44aefcb23930 100644 static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) { -@@ -801,6 +813,21 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +@@ -801,6 +809,21 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) return phy_mii_ioctl(netdev->phydev, rq, cmd); } @@ -145099,7 +159836,7 @@ index 2fa46baa589e..44aefcb23930 100644 static void smsc95xx_init_mac_address(struct usbnet *dev) { u8 addr[ETH_ALEN]; -@@ -824,6 +851,14 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) +@@ -824,6 +847,14 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) } } @@ -145114,7 +159851,7 @@ index 2fa46baa589e..44aefcb23930 100644 /* no useful static MAC address found. generate a random one */ eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -@@ -932,13 +967,13 @@ static int smsc95xx_reset(struct usbnet *dev) +@@ -932,13 +963,13 @@ static int smsc95xx_reset(struct usbnet *dev) if (!turbo_mode) { burst_cap = 0; @@ -145133,26 +159870,6 @@ index 2fa46baa589e..44aefcb23930 100644 } netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -@@ -1870,7 +1905,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(skb); - skb_trim(skb, skb->len - 4); /* remove fcs */ -- skb->truesize = size + sizeof(struct sk_buff); -+ if (truesize_mode) -+ skb->truesize = size + sizeof(struct sk_buff); - - return 1; - } -@@ -1888,7 +1924,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(ax_skb); - skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ -- ax_skb->truesize = size + sizeof(struct sk_buff); -+ if (truesize_mode) -+ ax_skb->truesize = size + sizeof(struct sk_buff); - - usbnet_skb_return(dev, ax_skb); - } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index fe31051a9e11..8c3613ff23f5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -145167,7 +159884,7 @@ index fe31051a9e11..8c3613ff23f5 100644 void brcmf_detach(struct device *dev); void brcmf_free(struct device *dev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -index c230bc8900a5..29cc020e0b15 100644 +index c708ae91c3ce..e19c14ba35f6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -9,6 +9,7 @@ @@ -145212,7 +159929,18 @@ index c230bc8900a5..29cc020e0b15 100644 brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", val); if (err) { -@@ -2216,7 +2224,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) +@@ -2162,6 +2170,10 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; ++ } else if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP) && ++ brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE_EXT)) { ++ brcmf_dbg(INFO, "using EXTSAE with PSK offload\n"); ++ profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; + } + break; + case WLAN_AKM_SUITE_FT_OVER_SAE: +@@ -2217,7 +2229,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp); skip_mfp_config: @@ -145221,7 +159949,7 @@ index c230bc8900a5..29cc020e0b15 100644 err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); if (err) { bphy_err(drvr, "could not set wpa_auth (%d)\n", err); -@@ -2461,43 +2469,50 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, +@@ -2462,43 +2474,52 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } @@ -145232,7 +159960,8 @@ index c230bc8900a5..29cc020e0b15 100644 - goto done; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) { + if (sme->crypto.psk) { -+ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { ++ if ((profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) && ++ (profile->use_fwsup != BRCMF_PROFILE_FWSUP_PSK)) { + if (WARN_ON(profile->use_fwsup != + BRCMF_PROFILE_FWSUP_NONE)) { + err = -EINVAL; @@ -145278,7 +160007,8 @@ index c230bc8900a5..29cc020e0b15 100644 - } - err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); - if (!err && sme->crypto.psk) -+ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { ++ if ((profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) && ++ sme->crypto.psk) { err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); + } else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { @@ -145302,7 +160032,7 @@ index c230bc8900a5..29cc020e0b15 100644 /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only */ -@@ -3298,7 +3313,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, +@@ -3299,7 +3320,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(INFO, "Do not enable power save for P2P clients\n"); pm = PM_OFF; } @@ -145311,7 +160041,7 @@ index c230bc8900a5..29cc020e0b15 100644 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); if (err) { -@@ -3308,6 +3323,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, +@@ -3309,6 +3330,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "error (%d)\n", err); } @@ -145319,7 +160049,7 @@ index c230bc8900a5..29cc020e0b15 100644 err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); if (err) -@@ -5509,9 +5525,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, +@@ -5517,9 +5539,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, s32 ie_len; struct brcmf_fil_action_frame_le *action_frame; struct brcmf_fil_af_params_le *af_params; @@ -145333,7 +160063,7 @@ index c230bc8900a5..29cc020e0b15 100644 brcmf_dbg(TRACE, "Enter\n"); -@@ -5592,6 +5611,71 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, +@@ -5600,6 +5625,71 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL); kfree(af_params); @@ -145405,7 +160135,7 @@ index c230bc8900a5..29cc020e0b15 100644 } else { brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len); -@@ -5915,6 +5999,40 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, +@@ -5923,6 +6013,40 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, return brcmf_set_pmk(ifp, NULL, 0); } @@ -145446,7 +160176,7 @@ index c230bc8900a5..29cc020e0b15 100644 static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, -@@ -5962,6 +6080,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { +@@ -5970,6 +6094,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .update_connect_params = brcmf_cfg80211_update_conn_params, .set_pmk = brcmf_cfg80211_set_pmk, .del_pmk = brcmf_cfg80211_del_pmk, @@ -145454,7 +160184,7 @@ index c230bc8900a5..29cc020e0b15 100644 }; struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings) -@@ -6008,6 +6127,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, +@@ -6016,6 +6141,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, vif->mbss = mbss; } @@ -145462,7 +160192,7 @@ index c230bc8900a5..29cc020e0b15 100644 list_add_tail(&vif->list, &cfg->vif_list); return vif; } -@@ -6699,6 +6819,122 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, +@@ -6707,6 +6833,122 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, return -EINVAL; } @@ -145585,7 +160315,7 @@ index c230bc8900a5..29cc020e0b15 100644 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { conf->frag_threshold = (u32)-1; -@@ -6743,7 +6979,16 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) +@@ -6751,7 +6993,16 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) brcmf_p2p_notify_action_tx_complete); brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP, brcmf_notify_connect_status); @@ -145603,7 +160333,7 @@ index c230bc8900a5..29cc020e0b15 100644 } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) -@@ -7331,6 +7576,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { +@@ -7338,6 +7589,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { .tx = 0xffff, .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | @@ -145611,7 +160341,7 @@ index c230bc8900a5..29cc020e0b15 100644 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) }, [NL80211_IFTYPE_P2P_CLIENT] = { -@@ -7636,6 +7882,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) +@@ -7643,6 +7895,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SAE_OFFLOAD_AP); } @@ -145620,7 +160350,7 @@ index c230bc8900a5..29cc020e0b15 100644 wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { -@@ -8177,31 +8425,45 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, +@@ -8184,31 +8438,45 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct brcmf_pub *drvr = cfg->pub; struct brcmf_fil_country_le ccreq; @@ -145836,17 +160566,34 @@ index 9bb5f709d41a..f3804d6f8768 100644 __printf(3, 4) void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c -index 909a34a1ab50..e300212f8763 100644 +index 909a34a1ab50..d0413f5acea6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c -@@ -44,6 +44,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { +@@ -44,6 +44,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { { BRCMF_FEAT_DOT11H, "802.11h" }, { BRCMF_FEAT_SAE, "sae" }, { BRCMF_FEAT_FWAUTH, "idauth" }, -+ { BRCMF_FEAT_SAE_EXT, "sae_ext " }, ++ { BRCMF_FEAT_SAE_EXT, "sae_ext" }, ++ { BRCMF_FEAT_SAE_EXT, "extsae" }, }; #ifdef DEBUG +@@ -240,7 +242,14 @@ static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) + brcmf_dbg(INFO, "[ %s]\n", caps); + + for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) { +- if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) { ++ const char *match = strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps)); ++ if (match) { ++ char endc; ++ if (match != caps && match[-1] != ' ') ++ continue; ++ endc = match[strlen(brcmf_fwcap_map[i].fwcap_id)]; ++ if (endc != '\0' && endc != ' ') ++ continue; + id = brcmf_fwcap_map[i].feature; + brcmf_dbg(INFO, "enabling feature: %s\n", + brcmf_feat_names[id]); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 7f4f0b3e4a7b..e2fc7c9dffdb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -146113,10 +160860,10 @@ index d4492d02e4ea..7376f9f37d07 100644 afx_hdl = &p2p->afx_hdl; afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -index 80220685f5e4..21a61f092820 100644 +index a43af8269140..b29e8d64d9af 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -@@ -2207,7 +2207,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, +@@ -2212,7 +2212,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, init_waitqueue_head(&devinfo->mbdata_resp_wait); @@ -146126,13 +160873,14 @@ index 80220685f5e4..21a61f092820 100644 goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -index 6b38d9de71af..8a95bb2573a1 100644 +index 6b38d9de71af..6f17fd3e5b92 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -35,9 +35,11 @@ +@@ -35,9 +35,12 @@ #include "core.h" #include "common.h" #include "bcdc.h" ++#include "debug.h" +#include "fwil.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) @@ -146141,7 +160889,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 /* watermark expressed in number of words */ #define DEFAULT_F2_WATERMARK 0x8 -@@ -325,7 +327,16 @@ struct rte_console { +@@ -325,7 +328,16 @@ struct rte_console { #define KSO_WAIT_US 50 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) @@ -146159,7 +160907,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 #ifdef DEBUG /* Device console log buffer state */ -@@ -609,6 +620,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); +@@ -609,6 +621,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); BRCMF_FW_DEF(4330, "brcmfmac4330-sdio"); BRCMF_FW_DEF(4334, "brcmfmac4334-sdio"); BRCMF_FW_DEF(43340, "brcmfmac43340-sdio"); @@ -146167,7 +160915,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 BRCMF_FW_DEF(4335, "brcmfmac4335-sdio"); BRCMF_FW_DEF(43362, "brcmfmac43362-sdio"); BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); -@@ -641,7 +653,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { +@@ -641,7 +654,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), @@ -146176,7 +160924,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), -@@ -1104,7 +1116,7 @@ static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) +@@ -1104,7 +1117,7 @@ static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) } #endif /* DEBUG */ @@ -146185,7 +160933,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 { struct brcmf_sdio_dev *sdiod = bus->sdiodev; struct brcmf_core *core = bus->sdio_core; -@@ -1193,6 +1205,9 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) +@@ -1193,6 +1206,9 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) brcmf_err("Unknown mailbox data content: 0x%02x\n", hmb_data); @@ -146195,7 +160943,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 return intstatus; } -@@ -2579,6 +2594,182 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) +@@ -2579,6 +2595,182 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) return ret; } @@ -146378,7 +161126,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 static void brcmf_sdio_dpc(struct brcmf_sdio *bus) { struct brcmf_sdio_dev *sdiod = bus->sdiodev; -@@ -2650,8 +2841,11 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) +@@ -2650,8 +2842,11 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) /* Handle host mailbox indication */ if (intstatus & I_HMB_HOST_INT) { @@ -146391,7 +161139,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 } sdio_release_host(bus->sdiodev->func1); -@@ -2696,7 +2890,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) +@@ -2696,7 +2891,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && @@ -146400,7 +161148,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 sdio_claim_host(bus->sdiodev->func1); if (bus->ctrl_frame_stat) { err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, -@@ -3566,6 +3760,10 @@ static int brcmf_sdio_bus_preinit(struct device *dev) +@@ -3566,6 +3761,10 @@ static int brcmf_sdio_bus_preinit(struct device *dev) if (err < 0) goto done; @@ -146411,7 +161159,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; if (sdiodev->sg_support) { bus->txglom = false; -@@ -4214,7 +4412,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, +@@ -4214,7 +4413,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, u8 saveclk, bpreq; u8 devctl; @@ -146420,7 +161168,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 if (err) goto fail; -@@ -4391,12 +4589,25 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, +@@ -4391,12 +4590,25 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, } /* Attach to the common layer, reserve hdr space */ @@ -146447,7 +161195,7 @@ index 6b38d9de71af..8a95bb2573a1 100644 /* ready */ return; -@@ -4639,3 +4850,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep) +@@ -4639,3 +4851,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep) return ret; } @@ -147158,7 +161906,7 @@ index a9a292d6d59b..2cc25b5811b9 100644 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); if (!new_prop) diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c -index e47a77f943b1..e0cb694ee60b 100644 +index e47a77f943b1..457a8d29fad8 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -14,6 +14,7 @@ @@ -147415,7 +162163,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* Limits operation to a specific generation (1, 2, or 3) */ static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) { -@@ -431,6 +553,99 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, +@@ -431,6 +553,111 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); } @@ -147434,6 +162182,18 @@ index e47a77f943b1..e0cb694ee60b 100644 + AXI_DIS_QOS_GATING_IN_MASTER; + writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); + ++ /* ++ * If the QOS_UPDATE_TIMING_FIX bit is Reserved-0, then this is a ++ * 2712C1 chip, or a single-lane RC. Use the best-effort alternative ++ * which is to partially throttle AXI requests in-flight to the SDC. ++ */ ++ reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ if (!(reg & AXI_EN_QOS_UPDATE_TIMING_FIX)) { ++ reg &= ~AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK; ++ reg |= 15; ++ writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); ++ } ++ + /* Disable VDM reception by default - QoS map defaults to 0 */ + reg = readl(pcie->base + PCIE_MISC_CTRL_1); + reg &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; @@ -147515,7 +162275,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static struct irq_chip brcm_msi_irq_chip = { .name = "BRCM STB PCIe MSI", .irq_ack = irq_chip_ack_parent, -@@ -440,14 +655,14 @@ static struct irq_chip brcm_msi_irq_chip = { +@@ -440,14 +667,14 @@ static struct irq_chip brcm_msi_irq_chip = { static struct msi_domain_info brcm_msi_domain_info = { .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | @@ -147532,7 +162292,7 @@ index e47a77f943b1..e0cb694ee60b 100644 struct brcm_msi *msi; struct device *dev; u32 bit; -@@ -459,10 +674,22 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc) +@@ -459,10 +686,22 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc) status = readl(msi->intr_base + MSI_INT_STATUS); status >>= msi->legacy_shift; @@ -147559,7 +162319,7 @@ index e47a77f943b1..e0cb694ee60b 100644 dev_dbg(dev, "unexpected MSI\n"); } -@@ -475,7 +702,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +@@ -475,7 +714,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) msg->address_lo = lower_32_bits(msi->target_addr); msg->address_hi = upper_32_bits(msi->target_addr); @@ -147568,7 +162328,7 @@ index e47a77f943b1..e0cb694ee60b 100644 } static int brcm_msi_set_affinity(struct irq_data *irq_data, -@@ -487,7 +714,7 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data, +@@ -487,7 +726,7 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data, static void brcm_msi_ack_irq(struct irq_data *data) { struct brcm_msi *msi = irq_data_get_irq_chip_data(data); @@ -147577,7 +162337,7 @@ index e47a77f943b1..e0cb694ee60b 100644 writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR); } -@@ -648,7 +875,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) +@@ -648,7 +887,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) msi->legacy_shift = 24; } else { msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; @@ -147586,7 +162346,7 @@ index e47a77f943b1..e0cb694ee60b 100644 msi->legacy_shift = 0; } -@@ -665,7 +892,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) +@@ -665,7 +904,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) } /* The controller is capable of serving in both RC and EP roles */ @@ -147595,7 +162355,7 @@ index e47a77f943b1..e0cb694ee60b 100644 { void __iomem *base = pcie->base; u32 val = readl(base + PCIE_MISC_PCIE_STATUS); -@@ -673,6 +900,14 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) +@@ -673,6 +912,14 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); } @@ -147610,7 +162370,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static bool brcm_pcie_link_up(struct brcm_pcie *pcie) { u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); -@@ -744,6 +979,18 @@ static void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) +@@ -744,6 +991,18 @@ static void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); } @@ -147629,7 +162389,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val) { if (WARN_ONCE(!pcie->perst_reset, "missing PERST# reset controller\n")) -@@ -765,6 +1012,16 @@ static void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val) +@@ -765,6 +1024,16 @@ static void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val) writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); } @@ -147646,7 +162406,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) { u32 tmp; -@@ -791,6 +1048,8 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, +@@ -791,6 +1060,8 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, size += entry->res->end - entry->res->start + 1; if (pcie_beg < lowest_pcie_addr) lowest_pcie_addr = pcie_beg; @@ -147655,7 +162415,7 @@ index e47a77f943b1..e0cb694ee60b 100644 } if (lowest_pcie_addr == ~(u64)0) { -@@ -861,6 +1120,30 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, +@@ -861,6 +1132,30 @@ static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, return 0; } @@ -147686,7 +162446,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static int brcm_pcie_setup(struct brcm_pcie *pcie) { u64 rc_bar2_offset, rc_bar2_size; -@@ -869,7 +1152,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -869,7 +1164,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) struct resource_entry *entry; u32 tmp, burst, aspm_support; int num_out_wins = 0; @@ -147695,7 +162455,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* Reset the bridge */ pcie->bridge_sw_init_set(pcie, 1); -@@ -892,6 +1175,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -892,6 +1187,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* Wait for SerDes to be stable */ usleep_range(100, 200); @@ -147713,7 +162473,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* * SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it -@@ -901,6 +1195,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -901,6 +1207,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) burst = 0x1; /* 256 bytes */ else if (pcie->type == BCM2711) burst = 0x0; /* 128 bytes */ @@ -147722,7 +162482,7 @@ index e47a77f943b1..e0cb694ee60b 100644 else if (pcie->type == BCM7278) burst = 0x3; /* 512 bytes */ else -@@ -908,16 +1204,18 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -908,16 +1216,18 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* * Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN, @@ -147744,7 +162504,7 @@ index e47a77f943b1..e0cb694ee60b 100644 ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, &rc_bar2_offset); if (ret) -@@ -930,7 +1228,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -930,7 +1240,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) writel(upper_32_bits(rc_bar2_offset), base + PCIE_MISC_RC_BAR2_CONFIG_HI); @@ -147756,7 +162516,7 @@ index e47a77f943b1..e0cb694ee60b 100644 for (memc = 0; memc < pcie->num_memc; memc++) { u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; -@@ -941,8 +1243,32 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -941,8 +1255,32 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) else if (memc == 2) u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); } @@ -147789,7 +162549,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* * We ideally want the MSI target address to be located in the 32bit * addressable memory area. Some devices might depend on it. This is -@@ -955,7 +1281,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -955,7 +1293,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) else pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; @@ -147798,7 +162558,7 @@ index e47a77f943b1..e0cb694ee60b 100644 dev_err(pcie->dev, "PCIe RC controller misconfigured as Endpoint\n"); return -EINVAL; } -@@ -979,6 +1305,38 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) +@@ -979,6 +1317,38 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); @@ -147837,7 +162597,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* * For config space accesses on the RC, show the right class for * a PCIe-PCIe bridge (the default setting is to be EP mode). -@@ -1032,13 +1390,31 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) +@@ -1032,13 +1402,31 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) { struct device *dev = pcie->dev; void __iomem *base = pcie->base; @@ -147872,7 +162632,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* * Wait for 100ms after PERST# deassertion; see PCIe CEM specification -@@ -1070,6 +1446,7 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) +@@ -1070,6 +1458,7 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) dev_err(dev, "failed attempt to enter ssc mode\n"); } @@ -147880,7 +162640,7 @@ index e47a77f943b1..e0cb694ee60b 100644 lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); -@@ -1078,13 +1455,15 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) +@@ -1078,13 +1467,15 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) ssc_good ? "(SSC)" : "(!SSC)"); /* @@ -147902,7 +162662,7 @@ index e47a77f943b1..e0cb694ee60b 100644 return 0; } -@@ -1192,6 +1571,7 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) +@@ -1192,6 +1583,7 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) { @@ -147910,7 +162670,7 @@ index e47a77f943b1..e0cb694ee60b 100644 static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT, PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT, -@@ -1224,6 +1604,9 @@ static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) +@@ -1224,6 +1616,9 @@ static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop")); return ret; @@ -147920,7 +162680,7 @@ index e47a77f943b1..e0cb694ee60b 100644 } static inline int brcm_phy_start(struct brcm_pcie *pcie) -@@ -1256,6 +1639,12 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) +@@ -1256,6 +1651,12 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); @@ -147933,7 +162693,7 @@ index e47a77f943b1..e0cb694ee60b 100644 /* Shutdown PCIe bridge */ pcie->bridge_sw_init_set(pcie, 1); } -@@ -1286,9 +1675,9 @@ static int brcm_pcie_suspend_noirq(struct device *dev) +@@ -1286,9 +1687,9 @@ static int brcm_pcie_suspend_noirq(struct device *dev) if (brcm_phy_stop(pcie)) dev_err(dev, "Could not stop phy for suspend\n"); @@ -147945,7 +162705,7 @@ index e47a77f943b1..e0cb694ee60b 100644 return ret; } -@@ -1383,7 +1772,7 @@ static int brcm_pcie_resume_noirq(struct device *dev) +@@ -1383,7 +1784,7 @@ static int brcm_pcie_resume_noirq(struct device *dev) if (pcie->sr) regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies); err_reset: @@ -147954,7 +162714,7 @@ index e47a77f943b1..e0cb694ee60b 100644 err_disable_clk: clk_disable_unprepare(pcie->clk); return ret; -@@ -1395,8 +1784,8 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie) +@@ -1395,8 +1796,8 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie) brcm_pcie_turn_off(pcie); if (brcm_phy_stop(pcie)) dev_err(pcie->dev, "Could not stop phy\n"); @@ -147965,7 +162725,7 @@ index e47a77f943b1..e0cb694ee60b 100644 clk_disable_unprepare(pcie->clk); } -@@ -1414,12 +1803,16 @@ static const int pcie_offsets[] = { +@@ -1414,12 +1815,16 @@ static const int pcie_offsets[] = { [RGR1_SW_INIT_1] = 0x9210, [EXT_CFG_INDEX] = 0x9000, [EXT_CFG_DATA] = 0x9004, @@ -147982,7 +162742,7 @@ index e47a77f943b1..e0cb694ee60b 100644 }; static const struct pcie_cfg_data generic_cfg = { -@@ -1427,6 +1820,7 @@ static const struct pcie_cfg_data generic_cfg = { +@@ -1427,6 +1832,7 @@ static const struct pcie_cfg_data generic_cfg = { .type = GENERIC, .perst_set = brcm_pcie_perst_set_generic, .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, @@ -147990,7 +162750,7 @@ index e47a77f943b1..e0cb694ee60b 100644 }; static const struct pcie_cfg_data bcm7425_cfg = { -@@ -1434,6 +1828,7 @@ static const struct pcie_cfg_data bcm7425_cfg = { +@@ -1434,6 +1840,7 @@ static const struct pcie_cfg_data bcm7425_cfg = { .type = BCM7425, .perst_set = brcm_pcie_perst_set_generic, .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, @@ -147998,7 +162758,7 @@ index e47a77f943b1..e0cb694ee60b 100644 }; static const struct pcie_cfg_data bcm7435_cfg = { -@@ -1448,12 +1843,15 @@ static const struct pcie_cfg_data bcm4908_cfg = { +@@ -1448,12 +1855,15 @@ static const struct pcie_cfg_data bcm4908_cfg = { .type = BCM4908, .perst_set = brcm_pcie_perst_set_4908, .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, @@ -148014,7 +162774,7 @@ index e47a77f943b1..e0cb694ee60b 100644 }; static const struct pcie_cfg_data bcm7278_cfg = { -@@ -1461,6 +1859,7 @@ static const struct pcie_cfg_data bcm7278_cfg = { +@@ -1461,6 +1871,7 @@ static const struct pcie_cfg_data bcm7278_cfg = { .type = BCM7278, .perst_set = brcm_pcie_perst_set_7278, .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, @@ -148022,7 +162782,7 @@ index e47a77f943b1..e0cb694ee60b 100644 }; static const struct pcie_cfg_data bcm2711_cfg = { -@@ -1468,10 +1867,27 @@ static const struct pcie_cfg_data bcm2711_cfg = { +@@ -1468,10 +1879,27 @@ static const struct pcie_cfg_data bcm2711_cfg = { .type = BCM2711, .perst_set = brcm_pcie_perst_set_generic, .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, @@ -148050,7 +162810,7 @@ index e47a77f943b1..e0cb694ee60b 100644 { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, -@@ -1512,7 +1928,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1512,7 +1940,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) data = of_device_get_match_data(&pdev->dev); if (!data) { @@ -148059,7 +162819,7 @@ index e47a77f943b1..e0cb694ee60b 100644 return -EINVAL; } -@@ -1523,6 +1939,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1523,6 +1951,7 @@ static int brcm_pcie_probe(struct platform_device *pdev) pcie->type = data->type; pcie->perst_set = data->perst_set; pcie->bridge_sw_init_set = data->bridge_sw_init_set; @@ -148067,7 +162827,7 @@ index e47a77f943b1..e0cb694ee60b 100644 pcie->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcie->base)) -@@ -1536,6 +1953,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1536,6 +1965,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) pcie->gen = (ret < 0) ? 0 : ret; pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); @@ -148077,7 +162837,7 @@ index e47a77f943b1..e0cb694ee60b 100644 ret = clk_prepare_enable(pcie->clk); if (ret) { -@@ -1552,14 +1972,20 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1552,14 +1984,20 @@ static int brcm_pcie_probe(struct platform_device *pdev) clk_disable_unprepare(pcie->clk); return PTR_ERR(pcie->perst_reset); } @@ -148100,7 +162860,7 @@ index e47a77f943b1..e0cb694ee60b 100644 clk_disable_unprepare(pcie->clk); return ret; } -@@ -1582,6 +2008,33 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1582,6 +2020,33 @@ static int brcm_pcie_probe(struct platform_device *pdev) dev_err(pcie->dev, "probe of internal MSI failed"); goto fail; } @@ -148134,7 +162894,7 @@ index e47a77f943b1..e0cb694ee60b 100644 } bridge->ops = pcie->type == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; -@@ -1598,6 +2051,8 @@ static int brcm_pcie_probe(struct platform_device *pdev) +@@ -1598,6 +2063,8 @@ static int brcm_pcie_probe(struct platform_device *pdev) return ret; } @@ -148144,10 +162904,10 @@ index e47a77f943b1..e0cb694ee60b 100644 fail: diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig -index 273d67ecf6d2..b73a4880578e 100644 +index 7b7b15f9bb6f..8de6595f1001 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig -@@ -208,6 +208,14 @@ config ALIBABA_UNCORE_DRW_PMU +@@ -220,6 +220,14 @@ config ALIBABA_UNCORE_DRW_PMU Support for Driveway PMU events monitoring on Yitian 710 DDR Sub-system. @@ -148163,10 +162923,10 @@ index 273d67ecf6d2..b73a4880578e 100644 config MARVELL_CN10K_DDR_PMU diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile -index 16b3ec4db916..d33610e432dc 100644 +index a8b7bc22e3d6..56bc50c79f78 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile -@@ -26,3 +26,4 @@ obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o +@@ -27,3 +27,4 @@ obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu/ obj-$(CONFIG_MESON_DDR_PMU) += amlogic/ obj-$(CONFIG_CXL_PMU) += cxl_pmu.o @@ -149234,7 +163994,7 @@ index 82b868ec1471..d298e4785829 100644 obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.o diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2712.c b/drivers/pinctrl/bcm/pinctrl-bcm2712.c new file mode 100644 -index 000000000000..80a6aea8d6c9 +index 000000000000..c349bcf05391 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm2712.c @@ -0,0 +1,1247 @@ @@ -150269,7 +165029,7 @@ index 000000000000..80a6aea8d6c9 + + *config = pinconf_to_config_packed(param, arg); + -+ return -ENOTSUPP; ++ return 0; +} + +static int bcm2712_pinconf_set(struct pinctrl_dev *pctldev, @@ -150591,10 +165351,10 @@ index 1489191a213f..cfb51cf2f766 100644 out_remove: diff --git a/drivers/pinctrl/pinctrl-rp1.c b/drivers/pinctrl/pinctrl-rp1.c new file mode 100644 -index 000000000000..6684b171e98b +index 000000000000..c3e9b83865e5 --- /dev/null +++ b/drivers/pinctrl/pinctrl-rp1.c -@@ -0,0 +1,1605 @@ +@@ -0,0 +1,1695 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Raspberry Pi RP1 GPIO unit (pinctrl + GPIO) @@ -150794,6 +165554,7 @@ index 000000000000..6684b171e98b + void __iomem *inte; + void __iomem *ints; + void __iomem *pad; ++ void __iomem *dummy; +}; + +enum funcs { @@ -150873,6 +165634,7 @@ index 000000000000..6684b171e98b + void __iomem *gpio_base; + void __iomem *rio_base; + void __iomem *pads_base; ++ void __iomem *dummy_base; + int irq[RP1_NUM_BANKS]; + struct rp1_pin_info pins[RP1_NUM_GPIOS]; + @@ -151174,6 +165936,42 @@ index 000000000000..6684b171e98b +module_param(persist_gpio_outputs, bool, 0644); +MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed"); + ++static bool pace_pin_updates = true; ++module_param(pace_pin_updates, bool, 0644); ++MODULE_PARM_DESC(pace_pin_updates, "Update pin states with guaranteed monotonicity if PCIe ASPM is enabled"); ++ ++static inline void rp1_pin_writel(u32 val, void __iomem *dummy, void __iomem *reg) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ /* ++ * Issuing 6 pipelined writes to the RC's Slot Control register will stall the ++ * peripheral bus inside 2712 if the link is in L1. This acts as a lightweight ++ * "fence" operation preventing back-to-back writes arriving at RP1 on a wake. ++ */ ++ if (dummy) { ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ writel_relaxed(0, dummy); ++ } ++ writel_relaxed(val, reg); ++ local_irq_restore(flags); ++} ++ ++static inline u32 rp1_pin_readl(const void __iomem *ioaddr) ++{ ++ /* ++ * Prior posted writes may not yet have been emitted by the CPU - do a store-flush ++ * before reading GPIO state, as this will serialise writes versus the next issued read. ++ */ ++ __dma_wmb(); ++ return readl(ioaddr); ++} ++ +static int rp1_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int offset, unsigned long *configs, + unsigned int num_configs); @@ -151200,12 +165998,12 @@ index 000000000000..6684b171e98b + +static void rp1_pad_update(struct rp1_pin_info *pin, u32 clr, u32 set) +{ -+ u32 padctrl = readl(pin->pad); ++ u32 padctrl = rp1_pin_readl(pin->pad); + + padctrl &= ~clr; + padctrl |= set; + -+ writel(padctrl, pin->pad); ++ rp1_pin_writel(padctrl, pin->dummy, pin->pad); +} + +static void rp1_input_enable(struct rp1_pin_info *pin, int value) @@ -151222,7 +166020,7 @@ index 000000000000..6684b171e98b + +static u32 rp1_get_fsel(struct rp1_pin_info *pin) +{ -+ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL); + u32 oeover = FLD_GET(ctrl, RP1_GPIO_CTRL_OEOVER); + u32 fsel = FLD_GET(ctrl, RP1_GPIO_CTRL_FUNCSEL); + @@ -151234,7 +166032,7 @@ index 000000000000..6684b171e98b + +static void rp1_set_fsel(struct rp1_pin_info *pin, u32 fsel) +{ -+ u32 ctrl = readl(pin->gpio + RP1_GPIO_CTRL); ++ u32 ctrl = rp1_pin_readl(pin->gpio + RP1_GPIO_CTRL); + + if (fsel >= RP1_FSEL_COUNT) + fsel = RP1_FSEL_NONE_HW; @@ -151249,12 +166047,12 @@ index 000000000000..6684b171e98b + FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI); + } + FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel); -+ writel(ctrl, pin->gpio + RP1_GPIO_CTRL); ++ rp1_pin_writel(ctrl, pin->dummy, pin->gpio + RP1_GPIO_CTRL); +} + +static int rp1_get_dir(struct rp1_pin_info *pin) +{ -+ return !(readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? ++ return !(rp1_pin_readl(pin->rio + RP1_RIO_OE) & (1 << pin->offset)) ? + RP1_DIR_INPUT : RP1_DIR_OUTPUT; +} + @@ -151262,19 +166060,19 @@ index 000000000000..6684b171e98b +{ + int offset = is_input ? RP1_CLR_OFFSET : RP1_SET_OFFSET; + -+ writel(1 << pin->offset, pin->rio + RP1_RIO_OE + offset); ++ rp1_pin_writel(1 << pin->offset, pin->dummy, pin->rio + RP1_RIO_OE + offset); +} + +static int rp1_get_value(struct rp1_pin_info *pin) +{ -+ return !!(readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); ++ return !!(rp1_pin_readl(pin->rio + RP1_RIO_IN) & (1 << pin->offset)); +} + +static void rp1_set_value(struct rp1_pin_info *pin, int value) +{ + /* Assume the pin is already an output */ -+ writel(1 << pin->offset, -+ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); ++ rp1_pin_writel(1 << pin->offset, pin->dummy, ++ pin->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)); +} + +static int rp1_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -151895,7 +166693,7 @@ index 000000000000..6684b171e98b + +static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg) +{ -+ u32 padctrl = readl(pin->pad); ++ u32 padctrl = rp1_pin_readl(pin->pad); + + FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3); + @@ -151995,7 +166793,7 @@ index 000000000000..6684b171e98b + if (!pin) + return -EINVAL; + -+ padctrl = readl(pin->pad); ++ padctrl = rp1_pin_readl(pin->pad); + + switch (param) { + case PIN_CONFIG_INPUT_ENABLE: @@ -152090,6 +166888,7 @@ index 000000000000..6684b171e98b +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; ++ struct device_node *rp1_node = NULL; + struct rp1_pinctrl *pc; + struct gpio_irq_chip *girq; + int err, i; @@ -152125,6 +166924,40 @@ index 000000000000..6684b171e98b + pc->gpio_chip = rp1_gpio_chip; + pc->gpio_chip.parent = dev; + ++ /* ++ * Workaround for the vagaries of PCIe on BCM2712 ++ * ++ * If the link to RP1 is in L1, then the BRCMSTB RC will buffer many ++ * outbound writes - and generate write responses for them, despite the ++ * fact that the link is not yet active. This has the effect of compressing ++ * multiple writes to GPIOs together, destroying any pacing that an application ++ * may require in the 1-10us range. ++ * ++ * The RC Slot Control configuration register is special. It emits a ++ * MsgD for every write to it, will stall further writes until the message ++ * goes out on the wire. This can be (ab)used to force CPU stalls when the ++ * link is inactive, at the cost of a small amount of downstream bandwidth ++ * and some 200ns of added latency for each write. ++ * ++ * Several back-to-back configuration writes are necessary to "fill the pipe", ++ * otherwise the outbound MAC can consume a pending MMIO write and reorder ++ * it with respect to the config writes - undoing the intent. ++ * ++ * of_iomap() is used directly here as the address overlaps with the RC driver's ++ * usage. ++ */ ++ rp1_node = of_find_node_by_name(NULL, "rp1"); ++ if (!rp1_node) ++ dev_err(&pdev->dev, "failed to find RP1 DT node\n"); ++ else if (pace_pin_updates && ++ of_device_is_compatible(rp1_node->parent, "brcm,bcm2712-pcie")) { ++ pc->dummy_base = of_iomap(rp1_node->parent, 0); ++ if (IS_ERR(pc->dummy_base)) { ++ dev_warn(&pdev->dev, "could not map bcm2712 root complex registers\n"); ++ pc->dummy_base = NULL; ++ } ++ } ++ + for (i = 0; i < RP1_NUM_BANKS; i++) { + const struct rp1_iobank_desc *bank = &rp1_iobanks[i]; + int j; @@ -152144,14 +166977,17 @@ index 000000000000..6684b171e98b + pin->rio = pc->rio_base + bank->rio_offset; + pin->pad = pc->pads_base + bank->pads_offset + + j * sizeof(u32); ++ pin->dummy = pc->dummy_base ? pc->dummy_base + 0xc0 : NULL; + } + + raw_spin_lock_init(&pc->irq_lock[i]); + } + + pc->pctl_dev = devm_pinctrl_register(dev, &rp1_pinctrl_desc, pc); -+ if (IS_ERR(pc->pctl_dev)) -+ return PTR_ERR(pc->pctl_dev); ++ if (IS_ERR(pc->pctl_dev)) { ++ err = PTR_ERR(pc->pctl_dev); ++ goto out_iounmap; ++ } + + girq = &pc->gpio_chip.irq; + girq->chip = &rp1_gpio_irq_chip; @@ -152180,7 +167016,7 @@ index 000000000000..6684b171e98b + err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); -+ return err; ++ goto out_iounmap; + } + + pc->gpio_range = rp1_pinctrl_gpio_range; @@ -152189,10 +167025,24 @@ index 000000000000..6684b171e98b + pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); + + return 0; ++ ++out_iounmap: ++ if (pc->dummy_base) ++ iounmap(pc->dummy_base); ++ return err; ++} ++ ++static void rp1_pinctrl_remove(struct platform_device *pdev) ++{ ++ struct rp1_pinctrl *pc = platform_get_drvdata(pdev); ++ ++ if (pc->dummy_base) ++ iounmap(pc->dummy_base); +} + +static struct platform_driver rp1_pinctrl_driver = { + .probe = rp1_pinctrl_probe, ++ .remove_new = rp1_pinctrl_remove, + .driver = { + .name = MODULE_NAME, + .of_match_table = rp1_pinctrl_match, @@ -152200,19 +167050,6 @@ index 000000000000..6684b171e98b + }, +}; +builtin_platform_driver(rp1_pinctrl_driver); -diff --git a/drivers/platform/x86/lenovo-yogabook.c b/drivers/platform/x86/lenovo-yogabook.c -index b8d0239192cb..fd62bf746ebd 100644 ---- a/drivers/platform/x86/lenovo-yogabook.c -+++ b/drivers/platform/x86/lenovo-yogabook.c -@@ -435,7 +435,7 @@ static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level) - .enabled = level, - }; - -- pwm_apply_state(data->kbd_bl_pwm, &state); -+ pwm_apply_might_sleep(data->kbd_bl_pwm, &state); - gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0); - return 0; - } diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c index d2f0233cb620..5812f2a355d4 100644 --- a/drivers/pmdomain/bcm/bcm2835-power.c @@ -152668,10 +167505,28 @@ index 5d19baae6a38..0675c8a2e560 100644 return pps_cdev_ioctl(file, cmd, arg); } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig -index 8ebcddf91f7b..1a6cecfa9ee3 100644 +index 8ebcddf91f7b..5adaa948c28b 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig -@@ -473,6 +473,15 @@ config PWM_RASPBERRYPI_POE +@@ -217,6 +217,17 @@ config PWM_FSL_FTM + To compile this driver as a module, choose M here: the module + will be called pwm-fsl-ftm. + ++config PWM_GPIO ++ tristate "GPIO PWM support" ++ depends on GPIOLIB ++ depends on HIGH_RES_TIMERS ++ help ++ Generic PWM framework driver for software PWM toggling a GPIO pin ++ from kernel high-resolution timers. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-gpio. ++ + config PWM_HIBVT + tristate "HiSilicon BVT PWM support" + depends on ARCH_HISI || COMPILE_TEST +@@ -473,6 +484,15 @@ config PWM_RASPBERRYPI_POE Enable Raspberry Pi firmware controller PWM bus used to control the official RPI PoE hat @@ -152688,10 +167543,18 @@ index 8ebcddf91f7b..1a6cecfa9ee3 100644 tristate "Renesas R-Car PWM support" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile -index c822389c2a24..920797b3ba8f 100644 +index c822389c2a24..58591a0a7d92 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile -@@ -43,6 +43,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o +@@ -18,6 +18,7 @@ obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o + obj-$(CONFIG_PWM_DWC) += pwm-dwc.o + obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o + obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o ++obj-$(CONFIG_PWM_GPIO) += pwm-gpio.o + obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o + obj-$(CONFIG_PWM_IMG) += pwm-img.o + obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o +@@ -43,6 +44,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o @@ -152700,30 +167563,19 @@ index c822389c2a24..920797b3ba8f 100644 obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c -index 0c8c63239adb..65331cd64da1 100644 +index a1a355ba2383..65331cd64da1 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c -@@ -382,8 +382,8 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, - } - EXPORT_SYMBOL_GPL(pwm_request_from_chip); - --static void pwm_apply_state_debug(struct pwm_device *pwm, -- const struct pwm_state *state) -+static void pwm_apply_debug(struct pwm_device *pwm, -+ const struct pwm_state *state) - { - struct pwm_state *last = &pwm->last; - struct pwm_chip *chip = pwm->chip; -@@ -489,24 +489,15 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, +@@ -489,24 +489,15 @@ static void pwm_apply_debug(struct pwm_device *pwm, } /** -- * pwm_apply_state() - atomically apply a new state to a PWM device +- * pwm_apply_might_sleep() - atomically apply a new state to a PWM device + * __pwm_apply() - atomically apply a new state to a PWM device * @pwm: PWM device * @state: new state to apply */ --int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) +-int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) +static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) { struct pwm_chip *chip; @@ -152732,7 +167584,7 @@ index 0c8c63239adb..65331cd64da1 100644 - /* - * Some lowlevel driver's implementations of .apply() make use of - * mutexes, also with some drivers only returning when the new -- * configuration is active calling pwm_apply_state() from atomic context +- * configuration is active calling pwm_apply_might_sleep() from atomic context - * is a bad idea. So make it explicit that calling this function might - * sleep. - */ @@ -152741,16 +167593,10 @@ index 0c8c63239adb..65331cd64da1 100644 if (!pwm || !state || !state->period || state->duty_cycle > state->period) return -EINVAL; -@@ -531,11 +522,60 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) - * only do this after pwm->state was applied as some - * implementations of .get_state depend on this - */ -- pwm_apply_state_debug(pwm, state); -+ pwm_apply_debug(pwm, state); +@@ -535,8 +526,57 @@ int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) return 0; } --EXPORT_SYMBOL_GPL(pwm_apply_state); + +/** + * pwm_apply_might_sleep() - atomically apply a new state to a PWM device @@ -152785,8 +167631,8 @@ index 0c8c63239adb..65331cd64da1 100644 + + return err; +} -+EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); -+ + EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); + +/** + * pwm_apply_atomic() - apply a new state to a PWM device from atomic context + * Not all PWM devices support this function, check with pwm_might_sleep(). @@ -152801,27 +167647,10 @@ index 0c8c63239adb..65331cd64da1 100644 + return __pwm_apply(pwm, state); +} +EXPORT_SYMBOL_GPL(pwm_apply_atomic); - ++ /** * pwm_capture() - capture and report a PWM signal -@@ -593,7 +633,7 @@ int pwm_adjust_config(struct pwm_device *pwm) - state.period = pargs.period; - state.polarity = pargs.polarity; - -- return pwm_apply_state(pwm, &state); -+ return pwm_apply_might_sleep(pwm, &state); - } - - /* -@@ -616,7 +656,7 @@ int pwm_adjust_config(struct pwm_device *pwm) - state.duty_cycle = state.period - state.duty_cycle; - } - -- return pwm_apply_state(pwm, &state); -+ return pwm_apply_might_sleep(pwm, &state); - } - EXPORT_SYMBOL_GPL(pwm_adjust_config); - + * @pwm: PWM device diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index bdfc2a5ec0d6..70e05ccd40ba 100644 --- a/drivers/pwm/pwm-bcm2835.c @@ -152958,6 +167787,252 @@ index bdfc2a5ec0d6..70e05ccd40ba 100644 }; module_platform_driver(bcm2835_pwm_driver); +diff --git a/drivers/pwm/pwm-gpio.c b/drivers/pwm/pwm-gpio.c +new file mode 100644 +index 000000000000..638d46f7a9fb +--- /dev/null ++++ b/drivers/pwm/pwm-gpio.c +@@ -0,0 +1,240 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Generic software PWM for modulating GPIOs ++ * ++ * Copyright (C) 2020 Axis Communications AB ++ * Copyright (C) 2020 Nicola Di Lieto ++ * Copyright (C) 2024 Stefan Wahren ++ * Copyright (C) 2024 Linus Walleij ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct pwm_gpio { ++ struct hrtimer gpio_timer; ++ struct gpio_desc *gpio; ++ struct pwm_state state; ++ struct pwm_state next_state; ++ ++ /* Protect internal state between pwm_ops and hrtimer */ ++ spinlock_t lock; ++ ++ bool changing; ++ bool running; ++ bool level; ++ struct pwm_chip chip; ++}; ++ ++static void pwm_gpio_round(struct pwm_state *dest, const struct pwm_state *src) ++{ ++ u64 dividend; ++ u32 remainder; ++ ++ *dest = *src; ++ ++ /* Round down to hrtimer resolution */ ++ dividend = dest->period; ++ remainder = do_div(dividend, hrtimer_resolution); ++ dest->period -= remainder; ++ ++ dividend = dest->duty_cycle; ++ remainder = do_div(dividend, hrtimer_resolution); ++ dest->duty_cycle -= remainder; ++} ++ ++static u64 pwm_gpio_toggle(struct pwm_gpio *gpwm, bool level) ++{ ++ const struct pwm_state *state = &gpwm->state; ++ bool invert = state->polarity == PWM_POLARITY_INVERSED; ++ ++ gpwm->level = level; ++ gpiod_set_value(gpwm->gpio, gpwm->level ^ invert); ++ ++ if (!state->duty_cycle || state->duty_cycle == state->period) { ++ gpwm->running = false; ++ return 0; ++ } ++ ++ gpwm->running = true; ++ return level ? state->duty_cycle : state->period - state->duty_cycle; ++} ++ ++static enum hrtimer_restart pwm_gpio_timer(struct hrtimer *gpio_timer) ++{ ++ struct pwm_gpio *gpwm = container_of(gpio_timer, struct pwm_gpio, ++ gpio_timer); ++ u64 next_toggle; ++ bool new_level; ++ ++ guard(spinlock_irqsave)(&gpwm->lock); ++ ++ /* Apply new state at end of current period */ ++ if (!gpwm->level && gpwm->changing) { ++ gpwm->changing = false; ++ gpwm->state = gpwm->next_state; ++ new_level = !!gpwm->state.duty_cycle; ++ } else { ++ new_level = !gpwm->level; ++ } ++ ++ next_toggle = pwm_gpio_toggle(gpwm, new_level); ++ if (next_toggle) ++ hrtimer_forward(gpio_timer, hrtimer_get_expires(gpio_timer), ++ ns_to_ktime(next_toggle)); ++ ++ return next_toggle ? HRTIMER_RESTART : HRTIMER_NORESTART; ++} ++ ++static int pwm_gpio_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct pwm_gpio *gpwm = container_of(chip, struct pwm_gpio, chip); ++ bool invert = state->polarity == PWM_POLARITY_INVERSED; ++ ++ if (state->duty_cycle && state->duty_cycle < hrtimer_resolution) ++ return -EINVAL; ++ ++ if (state->duty_cycle != state->period && ++ (state->period - state->duty_cycle < hrtimer_resolution)) ++ return -EINVAL; ++ ++ if (!state->enabled) { ++ hrtimer_cancel(&gpwm->gpio_timer); ++ } else if (!gpwm->running) { ++ int ret; ++ ++ /* ++ * This just enables the output, but pwm_gpio_toggle() ++ * really starts the duty cycle. ++ */ ++ ret = gpiod_direction_output(gpwm->gpio, invert); ++ if (ret) ++ return ret; ++ } ++ ++ guard(spinlock_irqsave)(&gpwm->lock); ++ ++ if (!state->enabled) { ++ pwm_gpio_round(&gpwm->state, state); ++ gpwm->running = false; ++ gpwm->changing = false; ++ ++ gpiod_set_value(gpwm->gpio, invert); ++ } else if (gpwm->running) { ++ pwm_gpio_round(&gpwm->next_state, state); ++ gpwm->changing = true; ++ } else { ++ unsigned long next_toggle; ++ ++ pwm_gpio_round(&gpwm->state, state); ++ gpwm->changing = false; ++ ++ next_toggle = pwm_gpio_toggle(gpwm, !!state->duty_cycle); ++ if (next_toggle) ++ hrtimer_start(&gpwm->gpio_timer, next_toggle, ++ HRTIMER_MODE_REL); ++ } ++ ++ return 0; ++} ++ ++static int pwm_gpio_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ++ struct pwm_state *state) ++{ ++ struct pwm_gpio *gpwm = container_of(chip, struct pwm_gpio, chip); ++ ++ guard(spinlock_irqsave)(&gpwm->lock); ++ ++ if (gpwm->changing) ++ *state = gpwm->next_state; ++ else ++ *state = gpwm->state; ++ ++ return 0; ++} ++ ++static const struct pwm_ops pwm_gpio_ops = { ++ .apply = pwm_gpio_apply, ++ .get_state = pwm_gpio_get_state, ++}; ++ ++static void pwm_gpio_disable_hrtimer(void *data) ++{ ++ struct pwm_gpio *gpwm = data; ++ ++ hrtimer_cancel(&gpwm->gpio_timer); ++} ++ ++static int pwm_gpio_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct pwm_chip *chip; ++ struct pwm_gpio *gpwm; ++ int ret; ++ ++ gpwm = devm_kzalloc(&pdev->dev, sizeof(*gpwm), GFP_KERNEL); ++ if (IS_ERR(gpwm)) ++ return PTR_ERR(gpwm); ++ ++ chip = &gpwm->chip; ++ ++ spin_lock_init(&gpwm->lock); ++ ++ gpwm->gpio = devm_gpiod_get(dev, NULL, GPIOD_ASIS); ++ if (IS_ERR(gpwm->gpio)) ++ return dev_err_probe(dev, PTR_ERR(gpwm->gpio), ++ "%pfw: could not get gpio\n", ++ dev_fwnode(dev)); ++ ++ if (gpiod_cansleep(gpwm->gpio)) ++ return dev_err_probe(dev, -EINVAL, ++ "%pfw: sleeping GPIO not supported\n", ++ dev_fwnode(dev)); ++ ++ chip->dev = dev; ++ chip->ops = &pwm_gpio_ops; ++ chip->atomic = true; ++ chip->npwm = 1; ++ ++ hrtimer_init(&gpwm->gpio_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ret = devm_add_action_or_reset(dev, pwm_gpio_disable_hrtimer, gpwm); ++ if (ret) ++ return ret; ++ ++ gpwm->gpio_timer.function = pwm_gpio_timer; ++ ++ return devm_pwmchip_add(dev, chip); ++} ++ ++static const struct of_device_id pwm_gpio_dt_ids[] = { ++ { .compatible = "pwm-gpio" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, pwm_gpio_dt_ids); ++ ++static struct platform_driver pwm_gpio_driver = { ++ .driver = { ++ .name = "pwm-gpio", ++ .of_match_table = pwm_gpio_dt_ids, ++ }, ++ .probe = pwm_gpio_probe, ++}; ++module_platform_driver(pwm_gpio_driver); ++ ++MODULE_DESCRIPTION("PWM GPIO driver"); ++MODULE_AUTHOR("Vincent Whitchurch"); ++MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c index 2939b71a7ba7..4cf3d6fd5011 100644 --- a/drivers/pwm/pwm-raspberrypi-poe.c @@ -153332,81 +168407,6 @@ index 000000000000..40ce14412817 +MODULE_AUTHOR("Naushir Patuck config even if state->period == - * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle - * because we might have exited early in the last call to -- * pwm_apply_state because of !state->enabled and so the two values in -+ * pwm_apply_might_sleep because of !state->enabled and so the two values in - * pwm->state might not be configured in hardware. - */ - ret = twl4030_pwmled_config(pwm->chip, pwm, -diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c -index 6d46db51daac..ba1204e18afb 100644 ---- a/drivers/pwm/pwm-vt8500.c -+++ b/drivers/pwm/pwm-vt8500.c -@@ -206,7 +206,7 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - * We cannot skip calling ->config even if state->period == - * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle - * because we might have exited early in the last call to -- * pwm_apply_state because of !state->enabled and so the two values in -+ * pwm_apply_might_sleep because of !state->enabled and so the two values in - * pwm->state might not be configured in hardware. - */ - err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period); -diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c -index 8d1254761e4d..052ccadbdabf 100644 ---- a/drivers/pwm/sysfs.c -+++ b/drivers/pwm/sysfs.c -@@ -62,7 +62,7 @@ static ssize_t period_store(struct device *child, - mutex_lock(&export->lock); - pwm_get_state(pwm, &state); - state.period = val; -- ret = pwm_apply_state(pwm, &state); -+ ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); - - return ret ? : size; -@@ -97,7 +97,7 @@ static ssize_t duty_cycle_store(struct device *child, - mutex_lock(&export->lock); - pwm_get_state(pwm, &state); - state.duty_cycle = val; -- ret = pwm_apply_state(pwm, &state); -+ ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); - - return ret ? : size; -@@ -144,7 +144,7 @@ static ssize_t enable_store(struct device *child, - goto unlock; - } - -- ret = pwm_apply_state(pwm, &state); -+ ret = pwm_apply_might_sleep(pwm, &state); - - unlock: - mutex_unlock(&export->lock); -@@ -194,7 +194,7 @@ static ssize_t polarity_store(struct device *child, - mutex_lock(&export->lock); - pwm_get_state(pwm, &state); - state.polarity = polarity; -- ret = pwm_apply_state(pwm, &state); -+ ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); - - return ret ? : size; -@@ -401,7 +401,7 @@ static int pwm_class_apply_state(struct pwm_export *export, - struct pwm_device *pwm, - struct pwm_state *state) - { -- int ret = pwm_apply_state(pwm, state); -+ int ret = pwm_apply_might_sleep(pwm, state); - - /* release lock taken in pwm_class_get_state */ - mutex_unlock(&export->lock); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 965d4f0c18a6..d6210b0c3bc5 100644 --- a/drivers/regulator/Kconfig @@ -153440,30 +168440,8 @@ index 23074714a81a..6a1cfb31fa43 100644 obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o -diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c -index e33d10df7a76..226ca4c62673 100644 ---- a/drivers/regulator/pwm-regulator.c -+++ b/drivers/regulator/pwm-regulator.c -@@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, - pwm_set_relative_duty_cycle(&pstate, - drvdata->duty_cycle_table[selector].dutycycle, 100); - -- ret = pwm_apply_state(drvdata->pwm, &pstate); -+ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); - if (ret) { - dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); - return ret; -@@ -219,7 +219,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, - - pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit); - -- ret = pwm_apply_state(drvdata->pwm, &pstate); -+ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); - if (ret) { - dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); - return ret; diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c -index f52c3d47ecea..ab0250fe2837 100644 +index f52c3d47ecea..152a45e3c478 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -143,24 +143,8 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) @@ -153474,14 +168452,14 @@ index f52c3d47ecea..ab0250fe2837 100644 - int ret, i; - - mutex_lock(&state->lock); -- + - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTC, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } - +- - mutex_unlock(&state->lock); - - if (ret < 0) @@ -153492,7 +168470,78 @@ index f52c3d47ecea..ab0250fe2837 100644 } static const struct regulator_init_data attiny_regulator_default = { -@@ -386,6 +370,14 @@ static void attiny_i2c_remove(struct i2c_client *client) +@@ -245,39 +229,6 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) + mutex_unlock(&state->lock); + } + +-static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) +-{ +- struct i2c_msg msgs[1]; +- u8 addr_buf[1] = { reg }; +- u8 data_buf[1] = { 0, }; +- int ret; +- +- /* Write register address */ +- msgs[0].addr = client->addr; +- msgs[0].flags = 0; +- msgs[0].len = ARRAY_SIZE(addr_buf); +- msgs[0].buf = addr_buf; +- +- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +- if (ret != ARRAY_SIZE(msgs)) +- return -EIO; +- +- usleep_range(5000, 10000); +- +- /* Read data from register */ +- msgs[0].addr = client->addr; +- msgs[0].flags = I2C_M_RD; +- msgs[0].len = 1; +- msgs[0].buf = data_buf; +- +- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +- if (ret != ARRAY_SIZE(msgs)) +- return -EIO; +- +- *buf = data_buf[0]; +- return 0; +-} +- + /* + * I2C driver interface functions + */ +@@ -289,7 +240,6 @@ static int attiny_i2c_probe(struct i2c_client *i2c) + struct regulator_dev *rdev; + struct attiny_lcd *state; + struct regmap *regmap; +- unsigned int data; + int ret; + + state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL); +@@ -307,22 +257,6 @@ static int attiny_i2c_probe(struct i2c_client *i2c) + goto error; + } + +- ret = attiny_i2c_read(i2c, REG_ID, &data); +- if (ret < 0) { +- dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); +- goto error; +- } +- +- switch (data) { +- case 0xde: /* ver 1 */ +- case 0xc3: /* ver 2 */ +- break; +- default: +- dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data); +- ret = -ENODEV; +- goto error; +- } +- + regmap_write(regmap, REG_POWERON, 0); + msleep(30); + regmap_write(regmap, REG_PWM, 0); +@@ -386,6 +320,14 @@ static void attiny_i2c_remove(struct i2c_client *client) mutex_destroy(&state->lock); } @@ -153507,7 +168556,7 @@ index f52c3d47ecea..ab0250fe2837 100644 static const struct of_device_id attiny_dt_ids[] = { { .compatible = "raspberrypi,7inch-touchscreen-panel-regulator" }, {}, -@@ -400,6 +392,7 @@ static struct i2c_driver attiny_regulator_driver = { +@@ -400,6 +342,7 @@ static struct i2c_driver attiny_regulator_driver = { }, .probe = attiny_i2c_probe, .remove = attiny_i2c_remove, @@ -153517,10 +168566,10 @@ index f52c3d47ecea..ab0250fe2837 100644 module_i2c_driver(attiny_regulator_driver); diff --git a/drivers/regulator/rpi-panel-v2-regulator.c b/drivers/regulator/rpi-panel-v2-regulator.c new file mode 100644 -index 000000000000..2a885f94e6b7 +index 000000000000..d94f3d501177 --- /dev/null +++ b/drivers/regulator/rpi-panel-v2-regulator.c -@@ -0,0 +1,189 @@ +@@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Raspberry Pi Ltd. @@ -153610,6 +168659,39 @@ index 000000000000..2a885f94e6b7 + .update_status = rpi_panel_v2_update_status, +}; + ++static int rpi_panel_v2_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) ++{ ++ struct i2c_msg msgs[1]; ++ u8 addr_buf[1] = { reg }; ++ u8 data_buf[1] = { 0, }; ++ int ret; ++ ++ /* Write register address */ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = 0; ++ msgs[0].len = ARRAY_SIZE(addr_buf); ++ msgs[0].buf = addr_buf; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret != ARRAY_SIZE(msgs)) ++ return -EIO; ++ ++ usleep_range(5000, 10000); ++ ++ /* Read data from register */ ++ msgs[0].addr = client->addr; ++ msgs[0].flags = I2C_M_RD; ++ msgs[0].len = 1; ++ msgs[0].buf = data_buf; ++ ++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret != ARRAY_SIZE(msgs)) ++ return -EIO; ++ ++ *buf = data_buf[0]; ++ return 0; ++} ++ +/* + * I2C driver interface functions + */ @@ -153627,6 +168709,7 @@ index 000000000000..2a885f94e6b7 + return -ENOMEM; + + mutex_init(&state->lock); ++ i2c_set_clientdata(i2c, state); + + regmap = devm_regmap_init_i2c(i2c, &rpi_panel_regmap_config); + if (IS_ERR(regmap)) { @@ -153636,7 +168719,7 @@ index 000000000000..2a885f94e6b7 + goto error; + } + -+ ret = regmap_read(regmap, REG_ID, &data); ++ ret = rpi_panel_v2_i2c_read(i2c, REG_ID, &data); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); + goto error; @@ -153691,6 +168774,21 @@ index 000000000000..2a885f94e6b7 + return ret; +} + ++static void rpi_panel_v2_i2c_remove(struct i2c_client *client) ++{ ++ struct rpi_panel_v2_lcd *state = i2c_get_clientdata(client); ++ ++ mutex_destroy(&state->lock); ++} ++ ++static void rpi_panel_v2_i2c_shutdown(struct i2c_client *client) ++{ ++ struct rpi_panel_v2_lcd *state = i2c_get_clientdata(client); ++ ++ regmap_write(state->regmap, REG_PWM, 0); ++ regmap_write(state->regmap, REG_POWERON, 0); ++} ++ +static const struct of_device_id rpi_panel_v2_dt_ids[] = { + { .compatible = "raspberrypi,v2-touchscreen-panel-regulator" }, + {}, @@ -153703,6 +168801,8 @@ index 000000000000..2a885f94e6b7 + .of_match_table = of_match_ptr(rpi_panel_v2_dt_ids), + }, + .probe = rpi_panel_v2_i2c_probe, ++ .remove = rpi_panel_v2_i2c_remove, ++ .shutdown = rpi_panel_v2_i2c_shutdown, +}; + +module_i2c_driver(rpi_panel_v2_regulator_driver); @@ -153823,7 +168923,7 @@ index e714661e61a9..89cda4dea7f8 100644 MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c -index d1efde3e7a80..6f95c7cd8afb 100644 +index d1efde3e7a80..b683a03264bd 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -100,6 +100,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -153834,11 +168934,15 @@ index d1efde3e7a80..6f95c7cd8afb 100644 int err; err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs, -@@ -110,6 +111,33 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) - if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS)) +@@ -107,9 +108,36 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) + if (err < 0) + return err; + +- if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS)) ++ if (regs[PCF8523_REG_CONTROL1] & PCF8523_CONTROL1_STOP) return -EINVAL; -+ if (regs[0] & PCF8523_SECONDS_OS) { ++ if (regs[PCF8523_REG_SECONDS] & PCF8523_SECONDS_OS) { + /* + * If the oscillator was stopped, try to clear the flag. Upon + * power-up the flag is always set, but if we cannot clear it @@ -153847,10 +168951,10 @@ index d1efde3e7a80..6f95c7cd8afb 100644 + * that the clock cannot be assumed to be correct. + */ + -+ regs[0] &= ~PCF8523_SECONDS_OS; ++ regs[PCF8523_REG_SECONDS] &= ~PCF8523_SECONDS_OS; + + err = regmap_write(pcf8523->regmap, PCF8523_REG_SECONDS, -+ regs[0]); ++ regs[PCF8523_REG_SECONDS]); + if (err < 0) + return err; + @@ -153862,7 +168966,7 @@ index d1efde3e7a80..6f95c7cd8afb 100644 + if (value & PCF8523_SECONDS_OS) + return -EAGAIN; + -+ regs[0] = value; ++ regs[PCF8523_REG_SECONDS] = value; + } + tm->tm_sec = bcd2bin(regs[3] & 0x7f); @@ -154213,6 +169317,41 @@ index f96906795fa6..3856477b14ff 100644 select PM_GENERIC_DOMAINS if PM help This enables support for the RPi power domains which can be enabled +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 60826b7ed21e..3f3e1fd9d7ff 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -846,6 +846,18 @@ config SPI_RB4XX + help + SPI controller driver for the Mikrotik RB4xx series boards. + ++config SPI_RP2040_GPIO_BRIDGE ++ tristate "Raspberry Pi RP2040 GPIO Bridge" ++ depends on I2C && SPI && GPIOLIB ++ help ++ Support for the Raspberry Pi RP2040 GPIO bridge. ++ ++ This driver provides support for the Raspberry Pi PR2040 GPIO bridge. ++ It can be used as a GPIO expander and a Tx-only SPI master. ++ ++ Optionally, this driver is able to take advantage of Raspberry Pi RP1 ++ GPIOs to achieve faster than I2C data transfer rates. ++ + config SPI_RPCIF + tristate "Renesas RPC-IF SPI driver" + depends on RENESAS_RPCIF +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 26bf16fcf890..a0e7d833b9d9 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -116,6 +116,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o + obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o + obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o + obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o ++obj-$(CONFIG_SPI_RP2040_GPIO_BRIDGE) += spi-rp2040-gpio-bridge.o + obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o + obj-$(CONFIG_SPI_RSPI) += spi-rspi.o + obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index e7bb2714678a..d3ad0f08d639 100644 --- a/drivers/spi/spi-bcm2835.c @@ -154324,61 +169463,341 @@ index e7bb2714678a..d3ad0f08d639 100644 if (IS_ERR(bs->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk), diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c -index 0274c9295514..86f33e6da447 100644 +index 0274c9295514..c3f5ee811fb1 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c -@@ -239,8 +239,11 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) +@@ -98,7 +98,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) + * support active-high or active-low CS level. + */ + if (cs_high == enable) +- dw_writel(dws, DW_SPI_SER, BIT(spi_get_chipselect(spi, 0))); ++ dw_writel(dws, DW_SPI_SER, ++ BIT(spi_get_csgpiod(spi, 0) ? 0 : spi_get_chipselect(spi, 0))); + else + dw_writel(dws, DW_SPI_SER, 0); + } +@@ -199,7 +200,18 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) + + /* Generically handle the erroneous situation */ + if (ret) { +- dw_spi_reset_chip(dws); ++ /* ++ * Forcibly halting the controller can cause DMA to hang. ++ * Defer to dw_spi_handle_err outside of interrupt context ++ * and mask further interrupts for the current transfer. ++ */ ++ if (dws->dma_mapped) { ++ dw_spi_mask_intr(dws, 0xff); ++ dw_readl(dws, DW_SPI_ICR); ++ } else { ++ dw_spi_reset_chip(dws); ++ } ++ + if (dws->host->cur_msg) + dws->host->cur_msg->status = ret; + } +@@ -208,6 +220,32 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) + } + EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE); + ++static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) ++{ ++ return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY; ++} ++ ++static enum hrtimer_restart dw_spi_hrtimer_handler(struct hrtimer *hr) ++{ ++ struct dw_spi *dws = container_of(hr, struct dw_spi, hrtimer); ++ ++ if (!dw_spi_ctlr_busy(dws)) { ++ spi_finalize_current_transfer(dws->host); ++ return HRTIMER_NORESTART; ++ } ++ ++ if (!dws->idle_wait_retries) { ++ dev_err(&dws->host->dev, "controller stuck at busy\n"); ++ spi_finalize_current_transfer(dws->host); ++ return HRTIMER_NORESTART; ++ } ++ ++ dws->idle_wait_retries--; ++ hrtimer_forward_now(hr, dws->idle_wait_interval); ++ ++ return HRTIMER_RESTART; ++} ++ + static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) + { + u16 irq_status = dw_readl(dws, DW_SPI_ISR); +@@ -224,12 +262,32 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) + * final stage of the transfer. By doing so we'll get the next IRQ + * right when the leftover incoming data is received. + */ +- dw_reader(dws); +- if (!dws->rx_len) { +- dw_spi_mask_intr(dws, 0xff); +- spi_finalize_current_transfer(dws->host); +- } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { +- dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); ++ if (dws->rx_len) { ++ dw_reader(dws); ++ if (!dws->rx_len) { ++ dw_spi_mask_intr(dws, 0xff); ++ spi_finalize_current_transfer(dws->host); ++ } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { ++ dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); ++ } ++ } else if (!dws->tx_len) { ++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); ++ if (dw_spi_ctlr_busy(dws)) { ++ ktime_t period = ns_to_ktime(DIV_ROUND_UP(NSEC_PER_SEC, dws->current_freq)); ++ ++ /* ++ * Make the initial wait an underestimate of how long the transfer ++ * should take, then poll rapidly to reduce the delay ++ */ ++ hrtimer_start(&dws->hrtimer, ++ period * (8 * dws->n_bytes - 1), ++ HRTIMER_MODE_REL); ++ dws->idle_wait_retries = 10; ++ dws->idle_wait_interval = period; ++ } else { ++ spi_finalize_current_transfer(dws->host); ++ } ++ return IRQ_HANDLED; + } + + /* +@@ -239,8 +297,12 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) */ if (irq_status & DW_SPI_INT_TXEI) { dw_writer(dws); - if (!dws->tx_len) +- dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); + if (!dws->tx_len) { - dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); -+ if (!dws->rx_len) -+ spi_finalize_current_transfer(dws->host); ++ if (dws->rx_len) ++ dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); ++ else ++ dw_writel(dws, DW_SPI_TXFTLR, 0); + } } return IRQ_HANDLED; -@@ -367,8 +370,11 @@ static void dw_spi_irq_setup(struct dw_spi *dws) +@@ -335,7 +397,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, + dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0); + + /* Note DW APB SSI clock divider doesn't support odd numbers */ +- clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe; ++ clk_div = min(DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1, 0xfffe) & 0xfffe; + speed_hz = dws->max_freq / clk_div; + + if (dws->current_freq != speed_hz) { +@@ -361,15 +423,18 @@ static void dw_spi_irq_setup(struct dw_spi *dws) + * will be adjusted at the final stage of the IRQ-based SPI transfer + * execution so not to lose the leftover of the incoming data. + */ +- level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len); ++ level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len ? dws->tx_len : dws->rx_len); + dw_writel(dws, DW_SPI_TXFTLR, level); + dw_writel(dws, DW_SPI_RXFTLR, level - 1); dws->transfer_handler = dw_spi_transfer_handler; - imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI | - DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; -+ imask = 0; -+ if (dws->tx_len) -+ imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI; ++ imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI; + if (dws->rx_len) + imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; dw_spi_umask_intr(dws, imask); ++ if (!dws->tx_len) ++ dw_writel(dws, DW_SPI_DR, 0); } + /* +@@ -392,18 +457,23 @@ static int dw_spi_poll_transfer(struct dw_spi *dws, + delay.unit = SPI_DELAY_UNIT_SCK; + nbits = dws->n_bytes * BITS_PER_BYTE; + ++ if (!dws->tx_len) ++ dw_writel(dws, DW_SPI_DR, 0); ++ + do { +- dw_writer(dws); ++ if (dws->tx_len) ++ dw_writer(dws); + + delay.value = nbits * (dws->rx_len - dws->tx_len); + spi_delay_exec(&delay, transfer); + +- dw_reader(dws); ++ if (dws->rx_len) ++ dw_reader(dws); + + ret = dw_spi_check_status(dws, true); + if (ret) + return ret; +- } while (dws->rx_len); ++ } while (dws->rx_len || dws->tx_len || dw_spi_ctlr_busy(dws)); + + return 0; + } +@@ -418,6 +488,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, + .dfs = transfer->bits_per_word, + .freq = transfer->speed_hz, + }; ++ int buswidth; + int ret; + + dws->dma_mapped = 0; +@@ -430,6 +501,23 @@ static int dw_spi_transfer_one(struct spi_controller *host, + dws->rx = transfer->rx_buf; + dws->rx_len = dws->tx_len; + ++ if (!dws->rx) { ++ dws->rx_len = 0; ++ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO; ++ } ++ ++ if (!dws->rx) { ++ dws->rx_len = 0; ++ cfg.tmode = DW_SPI_CTRLR0_TMOD_TO; ++ } ++ if (!dws->tx) { ++ dws->tx_len = 0; ++ cfg.tmode = DW_SPI_CTRLR0_TMOD_RO; ++ cfg.ndf = dws->rx_len; ++ } ++ buswidth = transfer->rx_buf ? transfer->rx_nbits : ++ (transfer->tx_buf ? transfer->tx_nbits : 1); ++ + /* Ensure the data above is visible for all CPUs */ + smp_mb(); + +@@ -609,11 +697,6 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi) + return 0; + } + +-static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) +-{ +- return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY; +-} +- + static int dw_spi_wait_mem_op_done(struct dw_spi *dws) + { + int retry = DW_SPI_WAIT_RETRIES; +@@ -947,10 +1030,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) + dev_warn(dev, "DMA init failed\n"); + } else { + host->can_dma = dws->dma_ops->can_dma; +- host->flags |= SPI_CONTROLLER_MUST_TX; + } + } + ++ hrtimer_init(&dws->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ++ dws->hrtimer.function = dw_spi_hrtimer_handler; ++ + ret = spi_register_controller(host); + if (ret) { + dev_err_probe(dev, ret, "problem registering spi host\n"); +@@ -976,6 +1061,7 @@ void dw_spi_remove_host(struct dw_spi *dws) + { + dw_spi_debugfs_remove(dws); + ++ hrtimer_cancel(&dws->hrtimer); + spi_unregister_controller(dws->host); + + if (dws->dma_ops && dws->dma_ops->dma_exit) diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c -index 0ecbb6c36e23..252ee087fef4 100644 +index 0ecbb6c36e23..93729275c63c 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c -@@ -315,8 +315,10 @@ static void dw_spi_dma_tx_done(void *arg) - struct dw_spi *dws = arg; +@@ -6,6 +6,7 @@ + */ - clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); -- if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) -+ if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) { -+ dw_writel(dws, DW_SPI_DMARDLR, 0); - return; + #include ++#include + #include + #include + #include +@@ -470,13 +471,12 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer) + u16 imr, dma_ctrl; + int ret; + +- if (!xfer->tx_buf) +- return -EINVAL; +- + /* Setup DMA channels */ +- ret = dw_spi_dma_config_tx(dws); +- if (ret) +- return ret; ++ if (xfer->tx_buf) { ++ ret = dw_spi_dma_config_tx(dws); ++ if (ret) ++ return ret; + } - complete(&dws->dma_completion); - } -@@ -642,6 +644,8 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer) + if (xfer->rx_buf) { + ret = dw_spi_dma_config_rx(dws); +@@ -485,13 +485,17 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer) + } - nents = max(xfer->tx_sg.nents, xfer->rx_sg.nents); + /* Set the DMA handshaking interface */ +- dma_ctrl = DW_SPI_DMACR_TDMAE; ++ dma_ctrl = 0; ++ if (xfer->tx_buf) ++ dma_ctrl |= DW_SPI_DMACR_TDMAE; + if (xfer->rx_buf) + dma_ctrl |= DW_SPI_DMACR_RDMAE; + dw_writel(dws, DW_SPI_DMACR, dma_ctrl); -+ dw_writel(dws, DW_SPI_DMARDLR, xfer->tx_buf ? (dws->rxburst - 1) : 0); + /* Set the interrupt mask */ +- imr = DW_SPI_INT_TXOI; ++ imr = 0; ++ if (xfer->tx_buf) ++ imr |= DW_SPI_INT_TXOI; + if (xfer->rx_buf) + imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI; + dw_spi_umask_intr(dws, imr); +@@ -508,15 +512,16 @@ static int dw_spi_dma_transfer_all(struct dw_spi *dws, + { + int ret; + +- /* Submit the DMA Tx transfer */ +- ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents); +- if (ret) +- goto err_clear_dmac; ++ /* Submit the DMA Tx transfer if required */ ++ if (xfer->tx_buf) { ++ ret = dw_spi_dma_submit_tx(dws, xfer->tx_sg.sgl, xfer->tx_sg.nents); ++ if (ret) ++ goto err_clear_dmac; ++ } + + /* Submit the DMA Rx transfer if required */ + if (xfer->rx_buf) { +- ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, +- xfer->rx_sg.nents); ++ ret = dw_spi_dma_submit_rx(dws, xfer->rx_sg.sgl, xfer->rx_sg.nents); + if (ret) + goto err_clear_dmac; + +@@ -524,7 +529,15 @@ static int dw_spi_dma_transfer_all(struct dw_spi *dws, + dma_async_issue_pending(dws->rxchan); + } + +- dma_async_issue_pending(dws->txchan); ++ if (xfer->tx_buf) { ++ dma_async_issue_pending(dws->txchan); ++ } else { ++ /* Pause to allow DMA channel to fetch RX descriptor */ ++ usleep_range(5, 10); + - /* - * Execute normal DMA-based transfer (which submits the Rx and Tx SG - * lists directly to the DMA engine at once) if either full hardware ++ /* Write something to the TX FIFO to start the transfer */ ++ dw_writel(dws, DW_SPI_DR, 0); ++ } + + ret = dw_spi_dma_wait(dws, xfer->len, xfer->effective_speed_hz); + diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 805264c9c65c..50bad1c13c37 100644 --- a/drivers/spi/spi-dw-mmio.c @@ -154405,6 +169824,20 @@ index 805264c9c65c..50bad1c13c37 100644 dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dwsmmio->clk)) +diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h +index 6cafeee8ee2a..6390c40935ec 100644 +--- a/drivers/spi/spi-dw.h ++++ b/drivers/spi/spi-dw.h +@@ -180,6 +180,9 @@ struct dw_spi { + u32 current_freq; /* frequency in hz */ + u32 cur_rx_sample_dly; + u32 def_rx_sample_dly_ns; ++ struct hrtimer hrtimer; ++ ktime_t idle_wait_interval; ++ int idle_wait_retries; + + /* Custom memory operations */ + struct spi_controller_mem_ops mem_ops; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index d8db4564b406..c95e4e9c14e3 100644 --- a/drivers/spi/spi-gpio.c @@ -154598,8 +170031,1258 @@ index d8db4564b406..c95e4e9c14e3 100644 } static int spi_gpio_probe(struct platform_device *pdev) +diff --git a/drivers/spi/spi-rp2040-gpio-bridge.c b/drivers/spi/spi-rp2040-gpio-bridge.c +new file mode 100644 +index 000000000000..418bd0ebb0c0 +--- /dev/null ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -0,0 +1,1244 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * RP2040 GPIO Bridge ++ * ++ * Copyright (C) 2023, 2024, Raspberry Pi Ltd ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "rp2040-gpio-bridge" ++ ++#define I2C_RETRIES 4U ++ ++#define ONE_KIB 1024U ++#define MD5_SUFFIX_SIZE 9U ++ ++#define RP2040_GBDG_FLASH_BLOCK_SIZE (8U * ONE_KIB) ++#define RP2040_GBDG_BLOCK_SIZE (RP2040_GBDG_FLASH_BLOCK_SIZE - MD5_SUFFIX_SIZE) ++ ++/* ++ * 1MiB transfer size is an arbitrary limit ++ * Max value is 4173330 (using a single manifest) ++ */ ++#define MAX_TRANSFER_SIZE (1024U * ONE_KIB) ++ ++#define HALF_BUFFER (4U * ONE_KIB) ++ ++#define STATUS_SIZE 4 ++#define MD5_DIGEST_SIZE 16 ++#define VERSION_SIZE 4 ++#define ID_SIZE 8 ++#define TOTAL_RD_HDR_SIZE \ ++ (STATUS_SIZE + MD5_DIGEST_SIZE + VERSION_SIZE + ID_SIZE) ++ ++struct rp2040_gbdg_device_info { ++ u8 md5[MD5_DIGEST_SIZE]; ++ u64 id; ++ u32 version; ++ u32 status; ++}; ++ ++static_assert(sizeof(struct rp2040_gbdg_device_info) == TOTAL_RD_HDR_SIZE); ++ ++#define MANIFEST_UNIT_SIZE 16 ++static_assert(MD5_DIGEST_SIZE == MANIFEST_UNIT_SIZE); ++#define MANIFEST_HEADER_UNITS 1 ++#define MANIFEST_DATA_UNITS \ ++ DIV_ROUND_UP(MAX_TRANSFER_SIZE, RP2040_GBDG_BLOCK_SIZE) ++ ++#define STATUS_BUSY 0x01 ++ ++#define DIRECT_PREFIX 0x00 ++#define DIRECT_CMD_CS 0x07 ++#define DIRECT_CMD_EMIT 0x08 ++ ++#define WRITE_DATA_PREFIX 0x80 ++#define WRITE_DATA_PREFIX_SIZE 1 ++ ++#define FIXED_SIZE_CMD_PREFIX 0x81 ++ ++#define WRITE_DATA_UPPER_PREFIX 0x82 ++#define WRITE_DATA_UPPER_PREFIX_SIZE 1 ++ ++#define NUM_GPIO 24 ++ ++enum rp2040_gbdg_fixed_size_commands { ++ /* 10-byte commands */ ++ CMD_SAVE_CACHE = 0x07, ++ CMD_SEND_RB = 0x08, ++ CMD_GPIO_ST_CL = 0x0b, ++ CMD_GPIO_OE = 0x0c, ++ CMD_DAT_RECV = 0x0d, ++ CMD_DAT_EMIT = 0x0e, ++ /* 18-byte commands */ ++ CMD_READ_CSUM = 0x11, ++ CMD_SEND_MANI = 0x13, ++}; ++ ++struct rp2040_gbdg { ++ struct spi_controller *controller; ++ ++ struct dentry *debugfs; ++ size_t transfer_progress; ++ ++ struct i2c_client *client; ++ struct crypto_shash *shash; ++ struct shash_desc *shash_desc; ++ ++ struct regulator *regulator; ++ ++ struct gpio_chip gc; ++ u32 gpio_requested; ++ u32 gpio_direction; ++ ++ bool fast_xfer_requires_i2c_lock; ++ struct gpio_descs *fast_xfer_gpios; ++ u32 fast_xfer_recv_gpio_base; ++ u8 fast_xfer_data_index; ++ u8 fast_xfer_clock_index; ++ void __iomem *gpio_base; ++ void __iomem *rio_base; ++ ++ bool bypass_cache; ++ ++ u8 buffer[2 + HALF_BUFFER]; ++ u8 manifest_prep[(MANIFEST_HEADER_UNITS + MANIFEST_DATA_UNITS) * ++ MANIFEST_UNIT_SIZE]; ++}; ++ ++static int rp2040_gbdg_gpio_dir_in(struct gpio_chip *gc, unsigned int offset); ++static void rp2040_gbdg_gpio_set(struct gpio_chip *gc, unsigned int offset, ++ int value); ++static int rp2040_gbdg_fast_xfer(struct rp2040_gbdg *priv_data, const u8 *data, ++ size_t len); ++ ++static int rp2040_gbdg_rp1_calc_offsets(u8 gpio, size_t *bank_offset, ++ u8 *shift_offset) ++{ ++ if (!bank_offset || !shift_offset || gpio >= 54) ++ return -EINVAL; ++ if (gpio < 28) { ++ *bank_offset = 0x0000; ++ *shift_offset = gpio; ++ } else if (gpio < 34) { ++ *bank_offset = 0x4000; ++ *shift_offset = gpio - 28; ++ } else { ++ *bank_offset = 0x8000; ++ *shift_offset = gpio - 34; ++ } ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_calc_mux_offset(u8 gpio, size_t *offset) ++{ ++ size_t bank_offset; ++ u8 shift_offset; ++ int ret; ++ ++ ret = rp2040_gbdg_rp1_calc_offsets(gpio, &bank_offset, &shift_offset); ++ if (ret) ++ return ret; ++ *offset = bank_offset + shift_offset * 8 + 0x4; ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_rp1_read_mux(struct rp2040_gbdg *priv_data, u8 gpio, ++ u32 *data) ++{ ++ size_t offset; ++ int ret; ++ ++ ret = rp2040_gbdg_calc_mux_offset(gpio, &offset); ++ if (ret) ++ return ret; ++ ++ *data = readl(priv_data->gpio_base + offset); ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_rp1_write_mux(struct rp2040_gbdg *priv_data, u8 gpio, ++ u32 val) ++{ ++ size_t offset; ++ int ret; ++ ++ ret = rp2040_gbdg_calc_mux_offset(gpio, &offset); ++ if (ret) ++ return ret; ++ ++ writel(val, priv_data->gpio_base + offset); ++ ++ return 0; ++} ++ ++static size_t rp2040_gbdg_max_transfer_size(struct spi_device *spi) ++{ ++ return MAX_TRANSFER_SIZE; ++} ++ ++static int rp2040_gbdg_get_device_info(struct i2c_client *client, ++ struct rp2040_gbdg_device_info *info) ++{ ++ u8 buf[TOTAL_RD_HDR_SIZE]; ++ u8 retries = I2C_RETRIES; ++ u8 *read_pos = buf; ++ size_t field_size; ++ int ret; ++ ++ do { ++ ret = i2c_master_recv(client, buf, sizeof(buf)); ++ if (!retries--) ++ break; ++ } while (ret == -ETIMEDOUT); ++ ++ if (ret != sizeof(buf)) ++ return ret < 0 ? ret : -EIO; ++ ++ field_size = sizeof_field(struct rp2040_gbdg_device_info, status); ++ memcpy(&info->status, read_pos, field_size); ++ read_pos += field_size; ++ ++ field_size = sizeof_field(struct rp2040_gbdg_device_info, md5); ++ memcpy(&info->md5, read_pos, field_size); ++ read_pos += field_size; ++ ++ field_size = sizeof_field(struct rp2040_gbdg_device_info, version); ++ memcpy(&info->version, read_pos, field_size); ++ read_pos += field_size; ++ ++ field_size = sizeof_field(struct rp2040_gbdg_device_info, id); ++ memcpy(&info->id, read_pos, field_size); ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_poll_device_info(struct i2c_client *client, ++ struct rp2040_gbdg_device_info *info) ++{ ++ struct rp2040_gbdg_device_info itnl; ++ int ret; ++ ++ itnl.status = STATUS_BUSY; ++ ++ while (itnl.status & STATUS_BUSY) { ++ ret = rp2040_gbdg_get_device_info(client, &itnl); ++ if (ret) ++ return ret; ++ } ++ memcpy(info, &itnl, sizeof(itnl)); ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_get_buffer_hash(struct i2c_client *client, u8 *md5) ++{ ++ struct rp2040_gbdg_device_info info; ++ int ret; ++ ++ ret = rp2040_gbdg_poll_device_info(client, &info); ++ if (ret) ++ return ret; ++ ++ memcpy(md5, info.md5, MD5_DIGEST_SIZE); ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_wait_until_free(struct i2c_client *client, u8 *status) ++{ ++ struct rp2040_gbdg_device_info info; ++ int ret; ++ ++ ret = rp2040_gbdg_poll_device_info(client, &info); ++ if (ret) ++ return ret; ++ ++ if (status) ++ *status = info.status; ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_i2c_send(struct i2c_client *client, const u8 *buf, ++ size_t len) ++{ ++ u8 retries = I2C_RETRIES; ++ int ret; ++ ++ ret = rp2040_gbdg_wait_until_free(client, NULL); ++ if (ret) { ++ dev_err(&client->dev, ++ "%s() rp2040_gbdg_wait_until_free failed\n", __func__); ++ return ret; ++ } ++ ++ do { ++ ret = i2c_master_send(client, buf, len); ++ if (!retries--) ++ break; ++ } while (ret == -ETIMEDOUT); ++ ++ if (ret != len) { ++ dev_err(&client->dev, "%s() i2c_master_send returned %d\n", ++ __func__, ret); ++ return ret < 0 ? ret : -EIO; ++ } ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_10byte_cmd(struct i2c_client *client, u8 cmd, u32 addr, ++ u32 len) ++{ ++ u8 buffer[10]; ++ ++ buffer[0] = FIXED_SIZE_CMD_PREFIX; ++ buffer[1] = cmd; ++ memcpy(&buffer[2], &addr, sizeof(addr)); ++ memcpy(&buffer[6], &len, sizeof(len)); ++ ++ return rp2040_gbdg_i2c_send(client, buffer, sizeof(buffer)); ++} ++ ++static int rp2040_gbdg_18byte_cmd(struct i2c_client *client, u8 cmd, ++ const u8 *digest) ++{ ++ u8 buffer[18]; ++ ++ buffer[0] = FIXED_SIZE_CMD_PREFIX; ++ buffer[1] = cmd; ++ memcpy(&buffer[2], digest, MD5_DIGEST_SIZE); ++ ++ return rp2040_gbdg_i2c_send(client, buffer, sizeof(buffer)); ++} ++ ++static int rp2040_gbdg_block_hash(struct rp2040_gbdg *priv_data, const u8 *data, ++ size_t len, u8 *out) ++{ ++ size_t remaining = RP2040_GBDG_BLOCK_SIZE; ++ size_t pad; ++ int ret; ++ ++ static const u8 padding[64] = { ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, ++ }; ++ ++ if (len > RP2040_GBDG_BLOCK_SIZE) { ++ return -EMSGSIZE; ++ } else if (len == RP2040_GBDG_BLOCK_SIZE) { ++ return crypto_shash_digest(priv_data->shash_desc, data, len, ++ out); ++ } else { ++ ret = crypto_shash_init(priv_data->shash_desc); ++ if (ret) ++ return ret; ++ ++ ret = crypto_shash_update(priv_data->shash_desc, data, len); ++ if (ret) ++ return ret; ++ remaining -= len; ++ ++ /* Pad up-to a 64-byte boundary, unless that takes us over. */ ++ pad = round_up(len, 64); ++ if (pad != len && pad < RP2040_GBDG_BLOCK_SIZE) { ++ ret = crypto_shash_update(priv_data->shash_desc, ++ padding, pad - len); ++ if (ret) ++ return ret; ++ remaining -= (pad - len); ++ } ++ ++ /* Pad up-to RP2040_GBDG_BLOCK_SIZE in, preferably, 64-byte chunks */ ++ while (remaining) { ++ pad = min_t(size_t, remaining, (size_t)64U); ++ ret = crypto_shash_update(priv_data->shash_desc, ++ padding, pad); ++ if (ret) ++ return ret; ++ remaining -= pad; ++ } ++ return crypto_shash_final(priv_data->shash_desc, out); ++ } ++} ++ ++static int rp2040_gbdg_set_remote_buffer_fast(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int len) ++{ ++ struct i2c_client *client = priv_data->client; ++ int ret; ++ ++ if (len > RP2040_GBDG_BLOCK_SIZE) ++ return -EMSGSIZE; ++ if (!priv_data->fast_xfer_gpios) ++ return -EIO; ++ ++ ret = rp2040_gbdg_10byte_cmd(client, CMD_DAT_RECV, ++ priv_data->fast_xfer_recv_gpio_base, len); ++ if (ret) { ++ dev_err(&client->dev, "%s() failed to enter fast data mode\n", ++ __func__); ++ return ret; ++ } ++ ++ return rp2040_gbdg_fast_xfer(priv_data, data, len); ++} ++ ++static int rp2040_gbdg_set_remote_buffer_i2c(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int len) ++{ ++ struct i2c_client *client = priv_data->client; ++ unsigned int write_len; ++ int ret; ++ ++ if (len > RP2040_GBDG_BLOCK_SIZE) ++ return -EMSGSIZE; ++ ++ priv_data->buffer[0] = WRITE_DATA_PREFIX; ++ write_len = min(len, HALF_BUFFER); ++ memcpy(&priv_data->buffer[1], data, write_len); ++ ++ ret = rp2040_gbdg_i2c_send(client, priv_data->buffer, write_len + 1); ++ if (ret) ++ return ret; ++ ++ len -= write_len; ++ data += write_len; ++ ++ if (!len) ++ return 0; ++ ++ priv_data->buffer[0] = WRITE_DATA_UPPER_PREFIX; ++ memcpy(&priv_data->buffer[1], data, len); ++ ret = rp2040_gbdg_i2c_send(client, priv_data->buffer, len + 1); ++ ++ return ret; ++} ++ ++static int rp2040_gbdg_set_remote_buffer(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int len) ++{ ++ if (priv_data->fast_xfer_gpios) ++ return rp2040_gbdg_set_remote_buffer_fast(priv_data, data, len); ++ else ++ return rp2040_gbdg_set_remote_buffer_i2c(priv_data, data, len); ++} ++ ++/* Loads data by checksum if available or resorts to sending byte-by-byte */ ++static int rp2040_gbdg_load_block_remote(struct rp2040_gbdg *priv_data, ++ const void *data, unsigned int len, ++ u8 *digest, bool persist) ++{ ++ u8 ascii_digest[MD5_DIGEST_SIZE * 2 + 1] = { 0 }; ++ struct i2c_client *client = priv_data->client; ++ u8 remote_digest[MD5_DIGEST_SIZE]; ++ u8 local_digest[MD5_DIGEST_SIZE]; ++ int ret; ++ ++ if (len > RP2040_GBDG_BLOCK_SIZE) ++ return -EMSGSIZE; ++ ++ ret = rp2040_gbdg_block_hash(priv_data, data, len, local_digest); ++ if (ret) ++ return ret; ++ ++ if (digest) ++ memcpy(digest, local_digest, MD5_DIGEST_SIZE); ++ ++ /* Check if the RP2040 has the data already */ ++ ret = rp2040_gbdg_18byte_cmd(client, CMD_READ_CSUM, local_digest); ++ if (ret) ++ return ret; ++ ++ ret = rp2040_gbdg_get_buffer_hash(client, remote_digest); ++ if (ret) ++ return ret; ++ ++ if (memcmp(local_digest, remote_digest, MD5_DIGEST_SIZE)) { ++ bin2hex(ascii_digest, local_digest, MD5_DIGEST_SIZE); ++ dev_info(&client->dev, "%s() device missing data: %s\n", ++ __func__, ascii_digest); ++ /* ++ * N.B. We're fine to send (the potentially shorter) transfer->len ++ * number of bytes here as the RP2040 will pad with 0xFF up to buffer ++ * size once we stop sending. ++ */ ++ ret = rp2040_gbdg_set_remote_buffer(priv_data, data, len); ++ if (ret) ++ return ret; ++ ++ /* Make sure the data actually arrived. */ ++ ret = rp2040_gbdg_get_buffer_hash(client, remote_digest); ++ if (memcmp(local_digest, remote_digest, MD5_DIGEST_SIZE)) { ++ dev_err(&priv_data->client->dev, ++ "%s() unable to send data to device\n", ++ __func__); ++ return -EREMOTEIO; ++ } ++ ++ if (persist) { ++ dev_info(&client->dev, ++ "%s() sent missing data to device, saving\n", ++ __func__); ++ ret = rp2040_gbdg_10byte_cmd(client, CMD_SAVE_CACHE, 0, ++ 0); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_transfer_block(struct rp2040_gbdg *priv_data, ++ const void *data, unsigned int len) ++{ ++ struct i2c_client *client = priv_data->client; ++ int ret; ++ ++ if (len > RP2040_GBDG_BLOCK_SIZE) ++ return -EMSGSIZE; ++ ++ ret = rp2040_gbdg_load_block_remote(priv_data, data, len, NULL, true); ++ if (ret) ++ return ret; ++ ++ /* Remote rambuffer now has correct contents, send it */ ++ ret = rp2040_gbdg_10byte_cmd(client, CMD_SEND_RB, 0, len); ++ if (ret) ++ return ret; ++ ++ /* ++ * Wait for data to have actually completed sending as we may be de-asserting CS too quickly ++ * otherwise. ++ */ ++ ret = rp2040_gbdg_wait_until_free(client, NULL); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_transfer_manifest(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int len) ++{ ++ struct i2c_client *client = priv_data->client; ++ static const char magic[] = "DATA_MANFST"; ++ unsigned int remaining = len; ++ const u32 data_length = len; ++ u8 digest[MD5_DIGEST_SIZE]; ++ u8 *digest_write_pos; ++ u8 status; ++ int ret; ++ ++ memcpy(priv_data->manifest_prep, magic, sizeof(magic)); ++ memcpy(priv_data->manifest_prep + sizeof(magic), &data_length, ++ sizeof(data_length)); ++ digest_write_pos = ++ priv_data->manifest_prep + sizeof(magic) + sizeof(data_length); ++ ++ while (remaining) { ++ unsigned int size = min(remaining, RP2040_GBDG_BLOCK_SIZE); ++ ++ ret = rp2040_gbdg_block_hash(priv_data, data, size, ++ digest_write_pos); ++ if (ret) ++ return ret; ++ ++ remaining -= size; ++ data += size; ++ digest_write_pos += MD5_DIGEST_SIZE; ++ } ++ ++ ret = rp2040_gbdg_load_block_remote( ++ priv_data, priv_data->manifest_prep, ++ digest_write_pos - priv_data->manifest_prep, digest, true); ++ if (ret) ++ return ret; ++ ++ dev_info(&client->dev, "%s() issue CMD_SEND_MANI\n", __func__); ++ ret = rp2040_gbdg_18byte_cmd(client, CMD_SEND_MANI, digest); ++ if (ret) ++ return ret; ++ ++ ret = rp2040_gbdg_wait_until_free(client, &status); ++ if (ret) ++ return ret; ++ ++ dev_info(&client->dev, "%s() SEND_MANI response: %02x\n", __func__, ++ status); ++ ++ return status; ++} ++ ++/* Precondition: correctly initialised fast_xfer_*, gpio_base, rio_base */ ++static int rp2040_gbdg_fast_xfer(struct rp2040_gbdg *priv_data, const u8 *data, ++ size_t len) ++{ ++ struct i2c_client *client = priv_data->client; ++ void __iomem *clock_toggle; ++ void __iomem *data_set; ++ size_t clock_bank; ++ size_t data_bank; ++ u8 clock_offset; ++ u8 data_offset; ++ u32 clock_mux; ++ u32 data_mux; ++ ++ if (priv_data->fast_xfer_requires_i2c_lock) ++ i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); ++ ++ rp2040_gbdg_rp1_read_mux(priv_data, priv_data->fast_xfer_data_index, ++ &data_mux); ++ rp2040_gbdg_rp1_read_mux(priv_data, priv_data->fast_xfer_clock_index, ++ &clock_mux); ++ ++ gpiod_direction_output(priv_data->fast_xfer_gpios->desc[0], 1); ++ gpiod_direction_output(priv_data->fast_xfer_gpios->desc[1], 0); ++ ++ rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_data_index, ++ &data_bank, &data_offset); ++ rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_clock_index, ++ &clock_bank, &clock_offset); ++ ++ data_set = priv_data->rio_base + data_bank + 0x2000; /* SET offset */ ++ clock_toggle = ++ priv_data->rio_base + clock_bank + 0x1000; /* XOR offset */ ++ ++ while (len--) { ++ /* MSB first ordering */ ++ u32 d = ~(*data++) << 4U; ++ /* ++ * Clock out each bit of data, LSB first ++ * (DDR, achieves approx 5 Mbps) ++ */ ++ for (size_t i = 0; i < 8; i++) { ++ /* Branchless set/clr data */ ++ writel(1 << data_offset, ++ data_set + ((d <<= 1) & 0x1000) /* CLR offset */ ++ ); ++ ++ /* Toggle the clock */ ++ writel(1 << clock_offset, clock_toggle); ++ } ++ } ++ ++ rp2040_gbdg_rp1_write_mux(priv_data, priv_data->fast_xfer_data_index, ++ data_mux); ++ rp2040_gbdg_rp1_write_mux(priv_data, priv_data->fast_xfer_clock_index, ++ clock_mux); ++ ++ if (priv_data->fast_xfer_requires_i2c_lock) ++ i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_transfer_bypass(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int length) ++{ ++ int ret; ++ u8 *buf; ++ ++ if (priv_data->fast_xfer_gpios) { ++ ret = rp2040_gbdg_10byte_cmd( ++ priv_data->client, CMD_DAT_EMIT, ++ priv_data->fast_xfer_recv_gpio_base, length); ++ return ret ? ret : ++ rp2040_gbdg_fast_xfer(priv_data, data, length); ++ } ++ ++ buf = priv_data->buffer; ++ ++ while (length) { ++ unsigned int xfer = min(length, HALF_BUFFER); ++ ++ buf[0] = DIRECT_PREFIX; ++ buf[1] = DIRECT_CMD_EMIT; ++ memcpy(&buf[2], data, xfer); ++ ret = rp2040_gbdg_i2c_send(priv_data->client, buf, xfer + 2); ++ if (ret) ++ return ret; ++ length -= xfer; ++ data += xfer; ++ } ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_transfer_cached(struct rp2040_gbdg *priv_data, ++ const u8 *data, unsigned int length) ++{ ++ int ret; ++ ++ /* ++ * Caching mechanism divides data into '8KiB - 9' (8183 byte) ++ * 'RP2040_GBDG_BLOCK_SIZE' blocks. ++ * ++ * If there's a large amount of data to send, instead, attempt to make use ++ * of a manifest. ++ */ ++ if (length > (2 * RP2040_GBDG_BLOCK_SIZE)) { ++ if (!rp2040_gbdg_transfer_manifest(priv_data, data, length)) ++ return 0; ++ } ++ ++ priv_data->transfer_progress = 0; ++ while (length) { ++ unsigned int xfer = min(length, RP2040_GBDG_BLOCK_SIZE); ++ ++ ret = rp2040_gbdg_transfer_block(priv_data, data, xfer); ++ if (ret) ++ return ret; ++ length -= xfer; ++ data += xfer; ++ priv_data->transfer_progress += xfer; ++ } ++ priv_data->transfer_progress = 0; ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_transfer_one(struct spi_controller *ctlr, ++ struct spi_device *spi, ++ struct spi_transfer *transfer) ++{ ++ /* All transfers are performed in a synchronous manner. As such, return '0' ++ * on success or -ve on failure. (Returning +ve indicates async xfer) ++ */ ++ ++ struct rp2040_gbdg *priv_data = spi_controller_get_devdata(ctlr); ++ ++ if (priv_data->bypass_cache) { ++ return rp2040_gbdg_transfer_bypass(priv_data, transfer->tx_buf, ++ transfer->len); ++ } else { ++ return rp2040_gbdg_transfer_cached(priv_data, transfer->tx_buf, ++ transfer->len); ++ } ++} ++ ++static void rp2040_gbdg_set_cs(struct spi_device *spi, bool enable) ++{ ++ static const char disable_cs[] = { DIRECT_PREFIX, DIRECT_CMD_CS, 0x00 }; ++ static const char enable_cs[] = { DIRECT_PREFIX, DIRECT_CMD_CS, 0x10 }; ++ struct rp2040_gbdg *p_data; ++ ++ p_data = spi_controller_get_devdata(spi->controller); ++ ++ /* ++ * 'enable' is inverted and instead describes the logic level of an ++ * active-low CS. ++ */ ++ rp2040_gbdg_i2c_send(p_data->client, enable ? disable_cs : enable_cs, ++ 3); ++} ++ ++static int rp2040_gbdg_gpio_request(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ u32 pattern; ++ int ret; ++ ++ if (offset >= NUM_GPIO) ++ return -EINVAL; ++ ++ pattern = (1 << (offset + 8)); ++ if (pattern & priv_data->gpio_requested) ++ return -EBUSY; ++ ++ /* Resume if previously no gpio requested */ ++ if (!priv_data->gpio_requested) { ++ ret = pm_runtime_resume_and_get(&priv_data->client->dev); ++ if (ret) { ++ dev_err(&priv_data->client->dev, ++ "%s(%u) unable to resume\n", __func__, offset); ++ return ret; ++ } ++ } ++ ++ priv_data->gpio_requested |= pattern; ++ ++ return 0; ++} ++ ++static void rp2040_gbdg_gpio_free(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ u32 pattern; ++ int ret; ++ ++ if (offset >= NUM_GPIO || !priv_data->gpio_requested) ++ return; ++ ++ pattern = (1 << (offset + 8)); ++ ++ priv_data->gpio_requested &= ~pattern; ++ rp2040_gbdg_gpio_dir_in(gc, offset); ++ rp2040_gbdg_gpio_set(gc, offset, 0); ++ ++ if (!priv_data->gpio_requested) { ++ ret = pm_runtime_put_autosuspend(&priv_data->client->dev); ++ if (ret) { ++ dev_err(&priv_data->client->dev, ++ "%s(%u) unable to put_autosuspend\n", __func__, ++ offset); ++ } ++ } ++} ++ ++static int rp2040_gbdg_gpio_get_direction(struct gpio_chip *gc, ++ unsigned int offset) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ ++ if (offset >= NUM_GPIO) ++ return -EINVAL; ++ ++ return (priv_data->gpio_direction & (1 << (offset + 8))) ? ++ GPIO_LINE_DIRECTION_IN : ++ GPIO_LINE_DIRECTION_OUT; ++} ++ ++static int rp2040_gbdg_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ struct i2c_client *client = priv_data->client; ++ ++ if (offset >= NUM_GPIO) ++ return -EINVAL; ++ ++ priv_data->gpio_direction |= (1 << (offset + 8)); ++ ++ return rp2040_gbdg_10byte_cmd(client, CMD_GPIO_OE, ++ ~priv_data->gpio_direction, ++ priv_data->gpio_direction); ++} ++ ++static int rp2040_gbdg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, ++ int value) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ struct i2c_client *client = priv_data->client; ++ u32 pattern; ++ int ret; ++ ++ if (offset >= NUM_GPIO) ++ return -EINVAL; ++ ++ pattern = (1 << (offset + 8)); ++ ++ ret = rp2040_gbdg_10byte_cmd(client, CMD_GPIO_ST_CL, ++ value ? pattern : 0, !value ? pattern : 0); ++ if (ret) { ++ dev_err(&client->dev, "%s(%u, %d) could not ST_CL\n", __func__, ++ offset, value); ++ return ret; ++ } ++ ++ priv_data->gpio_direction &= ~pattern; ++ ret = rp2040_gbdg_10byte_cmd(client, CMD_GPIO_OE, ++ ~priv_data->gpio_direction, ++ priv_data->gpio_direction); ++ ++ return ret; ++} ++ ++static int rp2040_gbdg_gpio_get(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ struct i2c_client *client = priv_data->client; ++ struct rp2040_gbdg_device_info info; ++ int ret; ++ ++ if (offset >= NUM_GPIO) ++ return -EINVAL; ++ ++ ret = rp2040_gbdg_get_device_info(client, &info); ++ if (ret) ++ return ret; ++ ++ return info.status & (1 << (offset + 8)) ? 1 : 0; ++} ++ ++static void rp2040_gbdg_gpio_set(struct gpio_chip *gc, unsigned int offset, ++ int value) ++{ ++ struct rp2040_gbdg *priv_data = gpiochip_get_data(gc); ++ struct i2c_client *client = priv_data->client; ++ u32 pattern; ++ ++ if (offset >= NUM_GPIO) ++ return; ++ ++ pattern = (1 << (offset + 8)); ++ rp2040_gbdg_10byte_cmd(client, CMD_GPIO_ST_CL, value ? pattern : 0, ++ !value ? pattern : 0); ++} ++ ++static int rp2040_gbdg_get_regulator(struct device *dev, ++ struct rp2040_gbdg *rp2040_gbdg) ++{ ++ struct regulator *reg = devm_regulator_get(dev, "power"); ++ ++ if (IS_ERR(reg)) ++ return PTR_ERR(reg); ++ ++ rp2040_gbdg->regulator = reg; ++ ++ return 0; ++} ++ ++static void rp2040_gbdg_parse_dt(struct rp2040_gbdg *rp2040_gbdg) ++{ ++ struct i2c_client *client = rp2040_gbdg->client; ++ struct of_phandle_args of_args[2] = { 0 }; ++ struct device *dev = &client->dev; ++ struct device_node *dn; ++ ++ rp2040_gbdg->bypass_cache = ++ of_property_read_bool(client->dev.of_node, "bypass-cache"); ++ ++ /* Optionally configure fast_xfer if RP1 is being used */ ++ if (of_parse_phandle_with_args(client->dev.of_node, "fast_xfer-gpios", ++ "#gpio-cells", 0, &of_args[0]) || ++ of_parse_phandle_with_args(client->dev.of_node, "fast_xfer-gpios", ++ "#gpio-cells", 1, &of_args[1])) { ++ dev_info(dev, "Could not parse fast_xfer-gpios phandles\n"); ++ goto node_put; ++ } ++ ++ if (of_args[0].np != of_args[1].np) { ++ dev_info( ++ dev, ++ "fast_xfer-gpios are not provided by the same controller\n"); ++ goto node_put; ++ } ++ dn = of_args[0].np; ++ if (!of_device_is_compatible(dn, "raspberrypi,rp1-gpio")) { ++ dev_info(dev, "fast_xfer-gpios controller is not an rp1\n"); ++ goto node_put; ++ } ++ if (of_args[0].args_count != 2 || of_args[1].args_count != 2) { ++ dev_info(dev, "of_args count is %d\n", of_args[0].args_count); ++ goto node_put; ++ } ++ ++ if (of_property_read_u32_index( ++ client->dev.of_node, "fast_xfer_recv_gpio_base", 0, ++ &rp2040_gbdg->fast_xfer_recv_gpio_base)) { ++ dev_info(dev, "Could not read fast_xfer_recv_gpio_base\n"); ++ goto node_put; ++ } ++ ++ rp2040_gbdg->fast_xfer_gpios = ++ devm_gpiod_get_array_optional(dev, "fast_xfer", GPIOD_ASIS); ++ if (!rp2040_gbdg->fast_xfer_gpios) { ++ dev_info(dev, "Could not acquire fast_xfer-gpios\n"); ++ goto node_put; ++ } ++ ++ rp2040_gbdg->fast_xfer_data_index = of_args[0].args[0]; ++ rp2040_gbdg->fast_xfer_clock_index = of_args[1].args[0]; ++ rp2040_gbdg->fast_xfer_requires_i2c_lock = of_property_read_bool( ++ client->dev.of_node, "fast_xfer_requires_i2c_lock"); ++ ++ rp2040_gbdg->gpio_base = of_iomap(dn, 0); ++ if (IS_ERR_OR_NULL(rp2040_gbdg->gpio_base)) { ++ dev_info(&client->dev, "%s() unable to map gpio_base\n", ++ __func__); ++ rp2040_gbdg->gpio_base = NULL; ++ devm_gpiod_put_array(dev, rp2040_gbdg->fast_xfer_gpios); ++ rp2040_gbdg->fast_xfer_gpios = NULL; ++ goto node_put; ++ } ++ ++ rp2040_gbdg->rio_base = of_iomap(dn, 1); ++ if (IS_ERR_OR_NULL(rp2040_gbdg->rio_base)) { ++ dev_info(&client->dev, "%s() unable to map rio_base\n", ++ __func__); ++ rp2040_gbdg->rio_base = NULL; ++ iounmap(rp2040_gbdg->gpio_base); ++ rp2040_gbdg->gpio_base = NULL; ++ devm_gpiod_put_array(dev, rp2040_gbdg->fast_xfer_gpios); ++ rp2040_gbdg->fast_xfer_gpios = NULL; ++ goto node_put; ++ } ++ ++node_put: ++ if (of_args[0].np) ++ of_node_put(of_args[0].np); ++ if (of_args[1].np) ++ of_node_put(of_args[1].np); ++} ++ ++static int rp2040_gbdg_power_off(struct rp2040_gbdg *rp2040_gbdg) ++{ ++ struct device *dev = &rp2040_gbdg->client->dev; ++ int ret; ++ ++ ret = regulator_disable(rp2040_gbdg->regulator); ++ if (ret) { ++ dev_err(dev, "%s: Could not disable regulator\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rp2040_gbdg_power_on(struct rp2040_gbdg *rp2040_gbdg) ++{ ++ struct device *dev = &rp2040_gbdg->client->dev; ++ int ret; ++ ++ ret = regulator_enable(rp2040_gbdg->regulator); ++ if (ret) { ++ dev_err(dev, "%s: Could not enable regulator\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int transfer_progress_show(struct seq_file *s, void *data) ++{ ++ struct rp2040_gbdg *rp2040_gbdg = s->private; ++ ++ seq_printf(s, "%zu\n", rp2040_gbdg->transfer_progress); ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(transfer_progress); ++ ++static int rp2040_gbdg_probe(struct i2c_client *client) ++{ ++ struct rp2040_gbdg_device_info info; ++ struct spi_controller *controller; ++ struct device *dev = &client->dev; ++ struct rp2040_gbdg *rp2040_gbdg; ++ struct device_node *np; ++ char debugfs_name[128]; ++ int ret; ++ ++ np = dev->of_node; ++ ++ controller = devm_spi_alloc_master(dev, sizeof(struct rp2040_gbdg)); ++ if (!controller) ++ return dev_err_probe(dev, ENOMEM, ++ "could not alloc spi controller\n"); ++ ++ rp2040_gbdg = spi_controller_get_devdata(controller); ++ i2c_set_clientdata(client, rp2040_gbdg); ++ rp2040_gbdg->controller = controller; ++ rp2040_gbdg->client = client; ++ ++ ret = rp2040_gbdg_get_regulator(dev, rp2040_gbdg); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, "Cannot get regulator\n"); ++ ++ ret = rp2040_gbdg_power_on(rp2040_gbdg); ++ if (ret) ++ return dev_err_probe(dev, ret, "Could not power on device\n"); ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_get_noresume(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, 1000); ++ pm_runtime_use_autosuspend(dev); ++ ++ ret = rp2040_gbdg_get_device_info(client, &info); ++ if (ret) { ++ dev_err(dev, "Could not get device info\n"); ++ goto err_pm; ++ } ++ ++ dev_info(dev, "%s() found dev ID: %llx, fw ver. %u\n", __func__, ++ info.id, info.version); ++ ++ rp2040_gbdg->shash = crypto_alloc_shash("md5", 0, 0); ++ if (IS_ERR(rp2040_gbdg->shash)) { ++ ret = PTR_ERR(rp2040_gbdg->shash); ++ dev_err(dev, "Could not allocate shash\n"); ++ goto err_pm; ++ } ++ ++ if (crypto_shash_digestsize(rp2040_gbdg->shash) != MD5_DIGEST_SIZE) { ++ ret = -EINVAL; ++ dev_err(dev, "error: Unexpected hash digest size\n"); ++ goto err_shash; ++ } ++ ++ rp2040_gbdg->shash_desc = ++ devm_kmalloc(dev, ++ sizeof(struct shash_desc) + ++ crypto_shash_descsize(rp2040_gbdg->shash), ++ 0); ++ ++ if (!rp2040_gbdg->shash_desc) { ++ ret = -ENOMEM; ++ dev_err(dev, ++ "error: Could not allocate memory for shash_desc\n"); ++ goto err_shash; ++ } ++ rp2040_gbdg->shash_desc->tfm = rp2040_gbdg->shash; ++ ++ controller->bus_num = -1; ++ controller->num_chipselect = 1; ++ controller->mode_bits = SPI_CPOL | SPI_CPHA; ++ controller->bits_per_word_mask = SPI_BPW_MASK(8); ++ controller->min_speed_hz = 35000000; ++ controller->max_speed_hz = 35000000; ++ controller->max_transfer_size = rp2040_gbdg_max_transfer_size; ++ controller->max_message_size = rp2040_gbdg_max_transfer_size; ++ controller->transfer_one = rp2040_gbdg_transfer_one; ++ controller->set_cs = rp2040_gbdg_set_cs; ++ ++ controller->dev.of_node = np; ++ controller->auto_runtime_pm = true; ++ ++ ret = devm_spi_register_controller(dev, controller); ++ if (ret) { ++ dev_err(dev, "error: Could not register SPI controller\n"); ++ goto err_shash; ++ } ++ ++ memset(&rp2040_gbdg->gc, 0, sizeof(struct gpio_chip)); ++ rp2040_gbdg->gc.parent = dev; ++ rp2040_gbdg->gc.label = MODULE_NAME; ++ rp2040_gbdg->gc.owner = THIS_MODULE; ++ rp2040_gbdg->gc.base = -1; ++ rp2040_gbdg->gc.ngpio = NUM_GPIO; ++ ++ rp2040_gbdg->gc.request = rp2040_gbdg_gpio_request; ++ rp2040_gbdg->gc.free = rp2040_gbdg_gpio_free; ++ rp2040_gbdg->gc.get_direction = rp2040_gbdg_gpio_get_direction; ++ rp2040_gbdg->gc.direction_input = rp2040_gbdg_gpio_dir_in; ++ rp2040_gbdg->gc.direction_output = rp2040_gbdg_gpio_dir_out; ++ rp2040_gbdg->gc.get = rp2040_gbdg_gpio_get; ++ rp2040_gbdg->gc.set = rp2040_gbdg_gpio_set; ++ rp2040_gbdg->gc.can_sleep = true; ++ ++ rp2040_gbdg->gpio_requested = 0; ++ ++ /* Coming out of reset, all GPIOs are inputs */ ++ rp2040_gbdg->gpio_direction = ~0; ++ ++ ret = devm_gpiochip_add_data(dev, &rp2040_gbdg->gc, rp2040_gbdg); ++ if (ret) { ++ dev_err(dev, "error: Could not add data to gpiochip\n"); ++ goto err_shash; ++ } ++ ++ rp2040_gbdg_parse_dt(rp2040_gbdg); ++ ++ snprintf(debugfs_name, sizeof(debugfs_name), "rp2040-spi:%s", ++ dev_name(dev)); ++ rp2040_gbdg->debugfs = debugfs_create_dir(debugfs_name, NULL); ++ debugfs_create_file("transfer_progress", 0444, rp2040_gbdg->debugfs, ++ rp2040_gbdg, &transfer_progress_fops); ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; ++ ++err_shash: ++ crypto_free_shash(rp2040_gbdg->shash); ++err_pm: ++ pm_runtime_disable(dev); ++ pm_runtime_put_noidle(dev); ++ rp2040_gbdg_power_off(rp2040_gbdg); ++ ++ return ret; ++} ++ ++static void rp2040_gbdg_remove(struct i2c_client *client) ++{ ++ struct rp2040_gbdg *priv_data = i2c_get_clientdata(client); ++ ++ crypto_free_shash(priv_data->shash); ++ ++ if (priv_data->gpio_base) { ++ iounmap(priv_data->gpio_base); ++ priv_data->gpio_base = NULL; ++ } ++ if (priv_data->rio_base) { ++ iounmap(priv_data->rio_base); ++ priv_data->rio_base = NULL; ++ } ++ ++ pm_runtime_disable(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) ++ rp2040_gbdg_power_off(priv_data); ++ pm_runtime_set_suspended(&client->dev); ++} ++ ++static const struct i2c_device_id rp2040_gbdg_id[] = { ++ { "rp2040-gpio-bridge", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(i2c, rp2040_gbdg_id); ++ ++static const struct of_device_id rp2040_gbdg_of_match[] = { ++ { .compatible = "raspberrypi,rp2040-gpio-bridge" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rp2040_gbdg_of_match); ++ ++static int rp2040_gbdg_runtime_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ return rp2040_gbdg_power_off(i2c_get_clientdata(client)); ++} ++ ++static int rp2040_gbdg_runtime_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ return rp2040_gbdg_power_on(i2c_get_clientdata(client)); ++} ++ ++static const struct dev_pm_ops rp2040_gbdg_pm_ops = { SET_RUNTIME_PM_OPS( ++ rp2040_gbdg_runtime_suspend, rp2040_gbdg_runtime_resume, NULL) }; ++ ++static struct i2c_driver rp2040_gbdg_driver = { ++ .driver = { ++ .name = MODULE_NAME, ++ .of_match_table = of_match_ptr(rp2040_gbdg_of_match), ++ .pm = &rp2040_gbdg_pm_ops, ++ }, ++ .probe = rp2040_gbdg_probe, ++ .remove = rp2040_gbdg_remove, ++ .id_table = rp2040_gbdg_id, ++}; ++ ++module_i2c_driver(rp2040_gbdg_driver); ++ ++MODULE_AUTHOR("Richard Oliver "); ++MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge"); ++MODULE_LICENSE("GPL"); ++MODULE_SOFTDEP("pre: md5"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index 1e08cd571d21..15d95f7172e2 100644 +index 91e067418bbb..5d8081e09ed7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3736,6 +3736,7 @@ static int spi_set_cs_timing(struct spi_device *spi) @@ -154626,7 +171309,7 @@ index 1e08cd571d21..15d95f7172e2 100644 * Help drivers fail *cleanly* when they need options * that aren't supported with their current controller. diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c -index d13dc15cc191..6fae5510b58f 100644 +index 16bb4fc3a4ba..0daf6e5e94a0 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -424,7 +424,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -154648,15 +171331,15 @@ index d13dc15cc191..6fae5510b58f 100644 tmp |= spi->mode & ~SPI_MODE_MASK; spi->mode = tmp & SPI_MODE_USER_MASK; retval = spi_setup(spi); -@@ -704,6 +699,7 @@ static const struct file_operations spidev_fops = { - static struct class *spidev_class; - - static const struct spi_device_id spidev_spi_ids[] = { +@@ -716,6 +711,7 @@ static const struct spi_device_id spidev_spi_ids[] = { + { .name = "spi-authenta" }, + { .name = "em3581" }, + { .name = "si3210" }, + { .name = "spidev" }, - { .name = "dh2228fv" }, - { .name = "ltc2488" }, - { .name = "sx1301" }, -@@ -724,7 +720,7 @@ MODULE_DEVICE_TABLE(spi, spidev_spi_ids); + {}, + }; + MODULE_DEVICE_TABLE(spi, spidev_spi_ids); +@@ -726,7 +722,7 @@ MODULE_DEVICE_TABLE(spi, spidev_spi_ids); */ static int spidev_of_check(struct device *dev) { @@ -155094,7 +171777,7 @@ index 000000000000..990257052b07 + rpivid_hw.o rpivid_h265.o diff --git a/drivers/staging/media/rpivid/rpivid.c b/drivers/staging/media/rpivid/rpivid.c new file mode 100644 -index 000000000000..70b9aa1ac48d +index 000000000000..8812d87a0810 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid.c @@ -0,0 +1,466 @@ @@ -155140,14 +171823,14 @@ index 000000000000..70b9aa1ac48d + .id = V4L2_CID_STATELESS_HEVC_SPS, + .ops = &rpivid_hevc_sps_ctrl_ops, + }, -+ .required = true, ++ .required = false, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_HEVC_PPS, + .ops = &rpivid_hevc_pps_ctrl_ops, + }, -+ .required = true, ++ .required = false, + }, + { + .cfg = { @@ -155902,10 +172585,10 @@ index 000000000000..8f15bb6406ab +#endif diff --git a/drivers/staging/media/rpivid/rpivid_h265.c b/drivers/staging/media/rpivid/rpivid_h265.c new file mode 100644 -index 000000000000..81ff98df1322 +index 000000000000..566f65caf2a9 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_h265.c -@@ -0,0 +1,2706 @@ +@@ -0,0 +1,2712 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Raspberry Pi HEVC driver @@ -157634,6 +174317,12 @@ index 000000000000..81ff98df1322 + unsigned int ctb_size_y; + bool sps_changed = false; + ++ if (!is_sps_set(run->h265.sps)) { ++ v4l2_warn(&dev->v4l2_dev, "SPS never set\n"); ++ goto fail; ++ } ++ // Can't check for PPS easily as all 0's looks valid to me ++ + if (memcmp(&s->sps, run->h265.sps, sizeof(s->sps)) != 0) { + /* SPS changed */ + v4l2_info(&dev->v4l2_dev, "SPS changed\n"); @@ -159312,10 +176001,10 @@ index 000000000000..ec73a2332b73 +#endif diff --git a/drivers/staging/media/rpivid/rpivid_video.c b/drivers/staging/media/rpivid/rpivid_video.c new file mode 100644 -index 000000000000..ef2dc2742ee9 +index 000000000000..3258910c17e4 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_video.c -@@ -0,0 +1,696 @@ +@@ -0,0 +1,691 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi HEVC driver @@ -159575,11 +176264,6 @@ index 000000000000..ef2dc2742ee9 + return 1; +} + -+static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps) -+{ -+ return sps && sps->pic_width_in_luma_samples != 0; -+} -+ +static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, + const int index) +{ @@ -160014,10 +176698,10 @@ index 000000000000..ef2dc2742ee9 +} diff --git a/drivers/staging/media/rpivid/rpivid_video.h b/drivers/staging/media/rpivid/rpivid_video.h new file mode 100644 -index 000000000000..e22cc0e32aa3 +index 000000000000..9db3a1968682 --- /dev/null +++ b/drivers/staging/media/rpivid/rpivid_video.h -@@ -0,0 +1,33 @@ +@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Raspberry Pi HEVC driver @@ -160040,6 +176724,11 @@ index 000000000000..e22cc0e32aa3 + unsigned int capabilities; +}; + ++static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps) ++{ ++ return sps && sps->pic_width_in_luma_samples != 0; ++} ++ +extern const struct v4l2_ioctl_ops rpivid_ioctl_ops; + +int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, @@ -160504,10 +177193,10 @@ index 000000000000..bc27a04ee9bd \ No newline at end of file diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c new file mode 100644 -index 000000000000..fed27d4cccd4 +index 000000000000..e065c07beda4 --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -0,0 +1,3964 @@ +@@ -0,0 +1,4019 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* @@ -162548,6 +179237,9 @@ index 000000000000..fed27d4cccd4 + struct v4l2_streamparm *parm) +{ + struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_DST]; ++ struct vchiq_mmal_port *port; ++ int ret; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; @@ -162563,7 +179255,44 @@ index 000000000000..fed27d4cccd4 + + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + -+ return 0; ++ /* ++ * If we have a component then setup the port as well. ++ * NB Framerate is passed to MMAL via the DST port, whilst V4L2 uses the ++ * OUTPUT queue. ++ */ ++ port = get_port_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ if (!port) ++ return 0; ++ ++ if (port->enabled) { ++ struct s32_fract frame_rate = { ctx->framerate_num, ++ ctx->framerate_denom }; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_VIDEO_FRAME_RATE, ++ &frame_rate, ++ sizeof(frame_rate)); ++ ++ return ret; ++ } ++ ++ setup_mmal_port_format(ctx, q_data, port); ++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); ++ if (ret) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", ++ __func__, ret); ++ ret = -EINVAL; ++ } ++ ++ if (q_data->sizeimage < port->minimum_buffer.size) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n", ++ __func__, q_data->sizeimage, ++ port->minimum_buffer.size); ++ ret = -EINVAL; ++ } ++ ++ return ret; +} + +static int vidioc_g_parm(struct file *file, void *priv, @@ -163201,6 +179930,13 @@ index 000000000000..fed27d4cccd4 + ¶ms, + sizeof(params)); + ++ } else if (dev->role == ENCODE) { ++ enable = 0; ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &ctx->component->control, ++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, ++ &enable, ++ sizeof(enable)); + } else if (dev->role == ENCODE_IMAGE) { + enable = 0; + vchiq_mmal_port_parameter_set(dev->instance, @@ -163334,8 +180070,14 @@ index 000000000000..fed27d4cccd4 + + if (*nbuffers < port->minimum_buffer.num) + *nbuffers = port->minimum_buffer.num; -+ /* Add one buffer to take an EOS */ -+ port->current_buffer.num = *nbuffers + 1; ++ ++ /* ++ * The VPU uses this number to allocate a pool of headers at port_enable. ++ * We can't increase it later, so use of CREATE_BUFS is going to result ++ * in bad things happening. Adopt worst-case allocation, and add one ++ * buffer to take an EOS ++ */ ++ port->current_buffer.num = VB2_MAX_FRAME + 1; + + return 0; +} @@ -163736,7 +180478,7 @@ index 000000000000..fed27d4cccd4 + case V4L2_PIX_FMT_H264: + ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, -+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | @@ -163750,7 +180492,9 @@ index 000000000000..fed27d4cccd4 + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1)), + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctrl = v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, @@ -165150,10 +181894,10 @@ index 000000000000..5ab232ff9bd9 +#endif diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c new file mode 100644 -index 000000000000..c10fc6af1897 +index 000000000000..2737417fa611 --- /dev/null +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c -@@ -0,0 +1,1816 @@ +@@ -0,0 +1,1833 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom BCM2835 ISP driver @@ -165295,6 +182039,8 @@ index 000000000000..c10fc6af1897 + /* Image pipeline controls. */ + int r_gain; + int b_gain; ++ struct dma_buf *last_ls_dmabuf; ++ struct mmal_parameter_lens_shading_v2 ls; +}; + +struct bcm2835_isp_buffer { @@ -165813,18 +182559,18 @@ index 000000000000..c10fc6af1897 + atomic_dec(&dev->num_streaming); + /* If all ports disabled, then disable the component */ + if (atomic_read(&dev->num_streaming) == 0) { -+ struct bcm2835_isp_lens_shading ls; + /* + * The ISP component on the firmware has a reference to the + * dmabuf handle for the lens shading table. Pass a null handle + * to remove that reference now. + */ -+ memset(&ls, 0, sizeof(ls)); ++ memset(&dev->ls, 0, sizeof(dev->ls)); + /* Must set a valid grid size for the FW */ -+ ls.grid_cell_size = 16; ++ dev->ls.grid_cell_size = 16; + set_isp_param(&dev->node[0], + MMAL_PARAMETER_LENS_SHADING_OVERRIDE, -+ &ls, sizeof(ls)); ++ &dev->ls, sizeof(dev->ls)); ++ dev->last_ls_dmabuf = NULL; + + ret = vchiq_mmal_component_disable(dev->mmal_instance, + dev->component); @@ -165875,6 +182621,36 @@ index 000000000000..c10fc6af1897 + return (bpl * height * fmt->size_multiplier_x2) >> 1; +} + ++static int map_ls_table(struct bcm2835_isp_dev *dev, struct dma_buf *dmabuf, ++ const struct bcm2835_isp_lens_shading *v4l2_ls) ++{ ++ void *vcsm_handle; ++ int ret; ++ ++ if (IS_ERR_OR_NULL(dmabuf)) ++ return -EINVAL; ++ ++ /* ++ * struct bcm2835_isp_lens_shading and struct ++ * mmal_parameter_lens_shading_v2 match so that we can do a ++ * simple memcpy here. ++ * Only the dmabuf to the actual table needs any manipulation. ++ */ ++ memcpy(&dev->ls, v4l2_ls, sizeof(dev->ls)); ++ ret = vc_sm_cma_import_dmabuf(dmabuf, &vcsm_handle); ++ if (ret) { ++ dma_buf_put(dmabuf); ++ return ret; ++ } ++ ++ dev->ls.mem_handle_table = vc_sm_cma_int_handle(vcsm_handle); ++ dev->last_ls_dmabuf = dmabuf; ++ ++ vc_sm_cma_free(vcsm_handle); ++ ++ return 0; ++} ++ +static int bcm2835_isp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct bcm2835_isp_dev *dev = @@ -165910,44 +182686,27 @@ index 000000000000..c10fc6af1897 + case V4L2_CID_USER_BCM2835_ISP_LENS_SHADING: + { + struct bcm2835_isp_lens_shading *v4l2_ls; -+ struct mmal_parameter_lens_shading_v2 ls; -+ struct dma_buf *dmabuf; -+ void *vcsm_handle; + + v4l2_ls = (struct bcm2835_isp_lens_shading *)ctrl->p_new.p_u8; -+ /* -+ * struct bcm2835_isp_lens_shading and struct -+ * mmal_parameter_lens_shading_v2 match so that we can do a -+ * simple memcpy here. -+ * Only the dmabuf to the actual table needs any manipulation. -+ */ -+ memcpy(&ls, v4l2_ls, sizeof(ls)); ++ struct dma_buf *dmabuf = dma_buf_get(v4l2_ls->dmabuf); + -+ dmabuf = dma_buf_get(v4l2_ls->dmabuf); -+ if (IS_ERR_OR_NULL(dmabuf)) -+ return -EINVAL; ++ if (dmabuf != dev->last_ls_dmabuf) ++ ret = map_ls_table(dev, dmabuf, v4l2_ls); + -+ ret = vc_sm_cma_import_dmabuf(dmabuf, &vcsm_handle); -+ if (ret) { -+ dma_buf_put(dmabuf); -+ return -EINVAL; -+ } -+ -+ ls.mem_handle_table = vc_sm_cma_int_handle(vcsm_handle); -+ if (ls.mem_handle_table) -+ /* The VPU will take a reference on the vcsm handle, ++ if (!ret && dev->ls.mem_handle_table) ++ /* ++ * The VPU will take a reference on the vcsm handle, + * which in turn will retain a reference on the dmabuf. + * This code can therefore safely release all + * references to the buffer. + */ -+ ret = set_isp_param(node, -+ MMAL_PARAMETER_LENS_SHADING_OVERRIDE, -+ &ls, -+ sizeof(ls)); ++ ret = ++ set_isp_param(node, ++ MMAL_PARAMETER_LENS_SHADING_OVERRIDE, ++ &dev->ls, sizeof(dev->ls)); + else + ret = -EINVAL; + -+ vc_sm_cma_free(vcsm_handle); + dma_buf_put(dmabuf); + break; + } @@ -166206,8 +182965,10 @@ index 000000000000..c10fc6af1897 + f->fmt.pix.quantization = V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, f->fmt.pix.colorspace, + f->fmt.pix.ycbcr_enc); + -+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, -+ fmt); ++ /* Respect any stride value (suitably aligned) that was requested. */ ++ f->fmt.pix.bytesperline = max(get_bytesperline(f->fmt.pix.width, fmt), ++ ALIGN(f->fmt.pix.bytesperline, ++ fmt->bytesperline_align)); + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.sizeimage = + get_sizeimage(f->fmt.pix.bytesperline, f->fmt.pix.width, @@ -171591,7 +188352,7 @@ index a17803da83f8..8099e6a261c2 100644 return status; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 362bbcdece0d..a5717655b388 100644 +index 362bbcdece0d..39fd89e8e663 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -152,6 +152,20 @@ static const struct vendor_data vendor_sbsa = { @@ -171615,7 +188376,20 @@ index 362bbcdece0d..a5717655b388 100644 #ifdef CONFIG_ACPI_SPCR_TABLE static const struct vendor_data vendor_qdt_qdf2400_e44 = { .reg_offset = pl011_std_offsets, -@@ -1456,6 +1470,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, +@@ -473,6 +487,12 @@ static void pl011_dma_probe(struct uart_amba_port *uap) + "RX DMA disabled - no residue processing\n"); + return; + } ++ /* ++ * DMA controllers with smaller burst capabilities than 1/4 ++ * the FIFO depth will leave more bytes than expected in the ++ * RX FIFO if mismatched. ++ */ ++ rx_conf.src_maxburst = min(caps.max_burst, rx_conf.src_maxburst); + } + dmaengine_slave_config(chan, &rx_conf); + uap->dmarx.chan = chan; +@@ -1456,6 +1476,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, return false; /* unable to transmit character */ pl011_write(c, uap, REG_DR); @@ -171623,7 +188397,7 @@ index 362bbcdece0d..a5717655b388 100644 uap->port.icount.tx++; return true; -@@ -1486,6 +1501,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) +@@ -1486,6 +1507,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) if (likely(from_irq) && count-- == 0) break; @@ -171634,7 +188408,7 @@ index 362bbcdece0d..a5717655b388 100644 if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) break; -@@ -2807,6 +2826,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +@@ -2807,6 +2832,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (IS_ERR(uap->clk)) return PTR_ERR(uap->clk); @@ -171646,7 +188420,7 @@ index 362bbcdece0d..a5717655b388 100644 uap->reg_offset = vendor->reg_offset; uap->vendor = vendor; uap->fifosize = vendor->get_fifosize(dev); -@@ -2969,6 +2993,88 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { +@@ -2969,6 +2999,88 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { }, }; @@ -171735,7 +188509,7 @@ index 362bbcdece0d..a5717655b388 100644 static const struct amba_id pl011_ids[] = { { .id = 0x00041011, -@@ -3002,6 +3108,8 @@ static int __init pl011_init(void) +@@ -3002,12 +3114,15 @@ static int __init pl011_init(void) if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); @@ -171744,11 +188518,18 @@ index 362bbcdece0d..a5717655b388 100644 return amba_driver_register(&pl011_driver); } + static void __exit pl011_exit(void) + { + platform_driver_unregister(&arm_sbsa_uart_platform_driver); ++ platform_driver_unregister(&pl011_axi_platform_driver); + amba_driver_unregister(&pl011_driver); + } + diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c -index f75b8bceb8ca..eea6622122af 100644 +index 673aeda71388..df6023ddaee0 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -760,6 +760,8 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +@@ -766,6 +766,8 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) if (rxlen) sc16is7xx_handle_rx(port, rxlen, iir); @@ -171757,7 +188538,7 @@ index f75b8bceb8ca..eea6622122af 100644 break; /* CTSRTS interrupt comes only when CTS goes inactive */ case SC16IS7XX_IIR_CTSRTS_SRC: -@@ -1191,6 +1193,9 @@ static int sc16is7xx_startup(struct uart_port *port) +@@ -1197,6 +1199,9 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_IER_MSI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); @@ -171768,7 +188549,7 @@ index f75b8bceb8ca..eea6622122af 100644 uart_port_lock_irqsave(port, &flags); sc16is7xx_enable_ms(port); diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 3a9a0dd4be70..64d602c5b238 100644 +index 949eca0adebe..80af388baede 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_COMMON) += common/ @@ -171813,10 +188594,10 @@ index 12b6dfeaf658..0de6ac768188 100644 * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must * have been called previously. Use for set_configuration, set_interface, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 7417972202b8..a3ed81c7674f 100644 +index 1ba3feb5e190..88e32e32929c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5709,7 +5709,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -5710,7 +5710,7 @@ static void port_event(struct usb_hub *hub, int port1) port_dev->over_current_count++; port_over_current_notify(port_dev); @@ -172095,10 +188876,10 @@ index db67df29fb2b..b16e528859a8 100644 } diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c -index 7d50c81ce97e..192c22bec46e 100644 +index fcb509059d7c..220d09c555d9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c -@@ -1162,6 +1162,24 @@ static void dwc3_config_threshold(struct dwc3 *dwc) +@@ -1208,6 +1208,24 @@ static void dwc3_config_threshold(struct dwc3 *dwc) } } @@ -172123,7 +188904,7 @@ index 7d50c81ce97e..192c22bec46e 100644 /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure -@@ -1242,6 +1260,8 @@ static int dwc3_core_init(struct dwc3 *dwc) +@@ -1273,6 +1291,8 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(dwc); @@ -172132,7 +188913,7 @@ index 7d50c81ce97e..192c22bec46e 100644 ret = dwc3_phy_power_on(dwc); if (ret) goto err_exit_phy; -@@ -1306,6 +1326,9 @@ static int dwc3_core_init(struct dwc3 *dwc) +@@ -1352,6 +1372,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->parkmode_disable_hs_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; @@ -172142,7 +188923,7 @@ index 7d50c81ce97e..192c22bec46e 100644 if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && (dwc->maximum_speed == USB_SPEED_HIGH || dwc->maximum_speed == USB_SPEED_FULL)) -@@ -1316,6 +1339,24 @@ static int dwc3_core_init(struct dwc3 *dwc) +@@ -1362,6 +1385,24 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_config_threshold(dwc); @@ -172167,7 +188948,7 @@ index 7d50c81ce97e..192c22bec46e 100644 return 0; err_power_off_phy: -@@ -1459,6 +1500,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) +@@ -1505,6 +1546,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) u8 tx_thr_num_pkt_prd = 0; u8 tx_max_burst_prd = 0; u8 tx_fifo_resize_max_num; @@ -172175,7 +188956,7 @@ index 7d50c81ce97e..192c22bec46e 100644 const char *usb_psy_name; int ret; -@@ -1481,6 +1523,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) +@@ -1527,6 +1569,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) */ tx_fifo_resize_max_num = 6; @@ -172185,7 +188966,7 @@ index 7d50c81ce97e..192c22bec46e 100644 dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = usb_get_dr_mode(dev); -@@ -1582,6 +1627,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) +@@ -1628,6 +1673,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,parkmode-disable-ss-quirk"); dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, "snps,parkmode-disable-hs-quirk"); @@ -172194,7 +188975,7 @@ index 7d50c81ce97e..192c22bec46e 100644 dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, "snps,gfladj-refclk-lpm-sel-quirk"); -@@ -1602,6 +1649,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) +@@ -1648,6 +1695,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->dis_split_quirk = device_property_read_bool(dev, "snps,dis-split-quirk"); @@ -172204,7 +188985,7 @@ index 7d50c81ce97e..192c22bec46e 100644 dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; -@@ -1619,6 +1669,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) +@@ -1665,6 +1715,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; dwc->tx_max_burst_prd = tx_max_burst_prd; @@ -172213,7 +188994,7 @@ index 7d50c81ce97e..192c22bec46e 100644 dwc->imod_interval = 0; dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; -@@ -1894,6 +1946,12 @@ static int dwc3_probe(struct platform_device *pdev) +@@ -1940,6 +1992,12 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_get_properties(dwc); @@ -172227,7 +189008,7 @@ index 7d50c81ce97e..192c22bec46e 100644 if (IS_ERR(dwc->reset)) { ret = PTR_ERR(dwc->reset); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h -index 5e6ead35dffc..7a7af6caae91 100644 +index 3325796f3cb4..1338b30466af 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -185,6 +185,9 @@ @@ -172248,7 +189029,7 @@ index 5e6ead35dffc..7a7af6caae91 100644 #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ -@@ -1060,6 +1064,7 @@ struct dwc3_scratchpad_array { +@@ -1061,6 +1065,7 @@ struct dwc3_scratchpad_array { * @tx_max_burst_prd: max periodic ESS transmit burst size * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @clear_stall_protocol: endpoint number that requires a delayed status phase @@ -172256,7 +189037,7 @@ index 5e6ead35dffc..7a7af6caae91 100644 * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise * @softconnect: true when gadget connect is called, false when disconnect runs -@@ -1111,10 +1116,12 @@ struct dwc3_scratchpad_array { +@@ -1112,10 +1117,12 @@ struct dwc3_scratchpad_array { * generation after resume from suspend. * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin * VBUS with an external supply. @@ -172273,7 +189054,7 @@ index 5e6ead35dffc..7a7af6caae91 100644 * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis -@@ -1293,6 +1300,7 @@ struct dwc3 { +@@ -1298,6 +1305,7 @@ struct dwc3 { u8 tx_max_burst_prd; u8 tx_fifo_resize_max_num; u8 clear_stall_protocol; @@ -172281,7 +189062,7 @@ index 5e6ead35dffc..7a7af6caae91 100644 const char *hsphy_interface; -@@ -1336,6 +1344,7 @@ struct dwc3 { +@@ -1341,6 +1349,7 @@ struct dwc3 { unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; unsigned parkmode_disable_hs_quirk:1; @@ -172290,10 +189071,10 @@ index 5e6ead35dffc..7a7af6caae91 100644 unsigned tx_de_emphasis_quirk:1; diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c -index f6a020d77fa1..799ab2a42995 100644 +index 6c143f7d2410..53c32d58706d 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c -@@ -61,16 +61,23 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) +@@ -82,16 +82,23 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) int dwc3_host_init(struct dwc3 *dwc) { @@ -176000,23 +192781,6 @@ index 000000000000..a896d73f7a93 + kref_put(&fsg->ref, fsg_release); +} +module_exit(fsg_cleanup); -diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c -index 9bf0e985acfa..d16c04d2961b 100644 ---- a/drivers/usb/gadget/function/uvc_configfs.c -+++ b/drivers/usb/gadget/function/uvc_configfs.c -@@ -92,10 +92,10 @@ static int __uvcg_iter_item_entries(const char *page, size_t len, - - while (pg - page < len) { - i = 0; -- while (i < sizeof(buf) && (pg - page < len) && -+ while (i < bufsize && (pg - page < len) && - *pg != '\0' && *pg != '\n') - buf[i++] = *pg++; -- if (i == sizeof(buf)) { -+ if (i == bufsize) { - ret = -EINVAL; - goto out_free_buf; - } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4448d0ab06f0..fdd73e4d4ad8 100644 --- a/drivers/usb/host/Kconfig @@ -205266,7 +222030,7 @@ index 000000000000..6a8be63a0ab2 +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c new file mode 100644 -index 000000000000..67e277804b2e +index 000000000000..6d9faea21462 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c @@ -0,0 +1,1433 @@ @@ -205512,8 +222276,8 @@ index 000000000000..67e277804b2e + hcdma_data_t hcdma; + int i = st->channel[n].dma_info.index; + int len; -+ struct fiq_dma_blob *blob = -+ (struct fiq_dma_blob *)(uintptr_t)st->dma_base; ++ struct fiq_dma_channel *split_dma = ++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base; + + len = fiq_get_xfer_len(st, n); + fiq_print(FIQDBG_INT, st, "LEN: %03d", len); @@ -205522,7 +222286,7 @@ index 000000000000..67e277804b2e + if (i > 6) + BUG(); + -+ hcdma.d32 = (u32)(uintptr_t)&blob->channel[n].index[i].buf[0]; ++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]); + FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA, hcdma.d32); + st->channel[n].dma_info.index = i; + return 0; @@ -205562,8 +222326,8 @@ index 000000000000..67e277804b2e + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + hcdma_data_t hcdma; -+ struct fiq_dma_blob *blob = -+ (struct fiq_dma_blob *)(uintptr_t)st->dma_base; ++ struct fiq_dma_channel *split_dma = ++ (struct fiq_dma_channel *)(uintptr_t)st->dma_base; + int last = 0; + int i = st->channel[n].dma_info.index; + @@ -205575,7 +222339,7 @@ index 000000000000..67e277804b2e + last = 1; + + /* New DMA address - address of bounce buffer referred to in index */ -+ hcdma.d32 = (u32)(uintptr_t)blob->channel[n].index[i].buf; ++ hcdma.d32 = lower_32_bits((uintptr_t)&split_dma[n].index[i].buf[0]); + //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA); + //hcdma.d32 += st->channel[n].dma_info.slot_len[i]; + fiq_print(FIQDBG_INT, st, "LAST: %01d ", last); @@ -206705,10 +223469,10 @@ index 000000000000..67e277804b2e +} diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h new file mode 100644 -index 000000000000..86b4aaf977fb +index 000000000000..8b080b7882fb --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h -@@ -0,0 +1,399 @@ +@@ -0,0 +1,395 @@ +/* + * dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions + * @@ -206974,10 +223738,6 @@ index 000000000000..86b4aaf977fb + struct fiq_split_dma_slot index[6]; +} __attribute__((packed)); + -+struct fiq_dma_blob { -+ struct fiq_dma_channel channel[0]; -+} __attribute__((packed)); -+ +/** + * struct fiq_hs_isoc_info - USB2.0 isochronous data + * @iso_frame: Pointer to the array of OTG URB iso_frame_descs. @@ -207063,7 +223823,7 @@ index 000000000000..86b4aaf977fb + mphi_regs_t mphi_regs; + void *dwc_regs_base; + dma_addr_t dma_base; -+ struct fiq_dma_blob *fiq_dmab; ++ struct fiq_dma_channel *fiq_dmab; + void *dummy_send; + dma_addr_t dummy_send_dma; + gintmsk_data_t gintmsk_saved; @@ -207076,7 +223836,7 @@ index 000000000000..86b4aaf977fb + char * buffer; + unsigned int bufsiz; +#endif -+ struct fiq_channel_state channel[0]; ++ struct fiq_channel_state channel[]; +}; + +#ifdef CONFIG_ARM64 @@ -207196,10 +223956,10 @@ index 000000000000..ffa8d21bc61e +END(_dwc_otg_fiq_stub) diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c new file mode 100644 -index 000000000000..6964784689fc +index 000000000000..fa35d944519c --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -0,0 +1,4366 @@ +@@ -0,0 +1,4364 @@ + +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $ @@ -207260,6 +224020,7 @@ index 000000000000..6964784689fc +static int last_sel_trans_num_avail_hc_at_end = 0; +#endif /* DEBUG_HOST_CHANNELS */ + ++static_assert(FIQ_PASSTHROUGH == 0); + +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) +{ @@ -208078,7 +224839,7 @@ index 000000000000..6964784689fc +void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num) +{ + struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; -+ struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab; + int i; + + st->fsm = FIQ_PASSTHROUGH; @@ -208100,7 +224861,7 @@ index 000000000000..6964784689fc + st->hs_isoc_info.iso_desc = NULL; + st->hs_isoc_info.nrframes = 0; + -+ DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128); ++ DWC_MEMSET(&split_dma[num].index[0], 0x6b, 1128); +} + +/** @@ -208247,9 +225008,6 @@ index 000000000000..6964784689fc + spin_lock_init(&hcd->fiq_state->lock); +#endif + -+ for (i = 0; i < num_channels; i++) { -+ hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; -+ } + hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16, + &hcd->fiq_state->dummy_send_dma); + @@ -208763,7 +225521,7 @@ index 000000000000..6964784689fc + int frame_length, i = 0; + uint8_t *ptr = NULL; + dwc_hc_t *hc = qh->channel; -+ struct fiq_dma_blob *blob; ++ struct fiq_dma_channel *split_dma; + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + + for (i = 0; i < 6; i++) { @@ -208778,10 +225536,10 @@ index 000000000000..6964784689fc + * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t) + * to point it to the correct offset in the allocated buffers. + */ -+ blob = (struct fiq_dma_blob *) ++ split_dma = (struct fiq_dma_channel *) + (uintptr_t)hcd->fiq_state->dma_base; -+ st->hcdma_copy.d32 =(u32)(uintptr_t) -+ blob->channel[hc->hc_num].index[0].buf; ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t) ++ &split_dma[hc->hc_num].index[0].buf[0]); + + /* Calculate the max number of CSPLITS such that the FIQ can time out + * a transaction if it fails. @@ -208802,7 +225560,7 @@ index 000000000000..6964784689fc + frame_length = frame_desc->length; + + /* Virtual address for bounce buffers */ -+ blob = hcd->fiq_dmab; ++ split_dma = hcd->fiq_dmab; + + ptr = qtd->urb->buf + frame_desc->offset; + if (frame_length == 0) { @@ -208815,11 +225573,11 @@ index 000000000000..6964784689fc + } else { + do { + if (frame_length <= 188) { -+ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length); ++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, frame_length); + st->dma_info.slot_len[i] = frame_length; + ptr += frame_length; + } else { -+ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188); ++ dwc_memcpy(&split_dma[hc->hc_num].index[i].buf[0], ptr, 188); + st->dma_info.slot_len[i] = 188; + ptr += 188; + } @@ -208836,10 +225594,10 @@ index 000000000000..6964784689fc + * dma_addr_t) to point it to the correct offset in the + * allocated buffers. + */ -+ blob = (struct fiq_dma_blob *) ++ split_dma = (struct fiq_dma_channel *) + (uintptr_t)hcd->fiq_state->dma_base; -+ st->hcdma_copy.d32 = (u32)(uintptr_t) -+ blob->channel[hc->hc_num].index[0].buf; ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t) ++ &split_dma[hc->hc_num].index[0].buf[0]); + + /* fixup xfersize to the actual packet size */ + st->hctsiz_copy.b.pid = 0; @@ -209119,14 +225877,14 @@ index 000000000000..6964784689fc + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { -+ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + } else { + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { -+ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + /* The FIQ depends upon no other interrupts being enabled except channel halt. @@ -209146,7 +225904,7 @@ index 000000000000..6964784689fc + if (hc->align_buff) { + st->hcdma_copy.d32 = hc->align_buff; + } else { -+ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ st->hcdma_copy.d32 = lower_32_bits((uintptr_t)hc->xfer_buff); + } + } + DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); @@ -211568,7 +228326,7 @@ index 000000000000..6964784689fc +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h new file mode 100644 -index 000000000000..5ed8dccf0395 +index 000000000000..e0611c1592b1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h @@ -0,0 +1,870 @@ @@ -211662,7 +228420,7 @@ index 000000000000..5ed8dccf0395 + uint32_t flags; + uint16_t interval; + struct dwc_otg_hcd_pipe_info pipe_info; -+ struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; ++ struct dwc_otg_hcd_iso_packet_desc iso_descs[]; +}; + +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe) @@ -212166,7 +228924,7 @@ index 000000000000..5ed8dccf0395 + struct fiq_state *fiq_state; + + /** Virtual address for split transaction DMA bounce buffers */ -+ struct fiq_dma_blob *fiq_dmab; ++ struct fiq_dma_channel *fiq_dmab; + +#ifdef DEBUG + uint32_t frrem_samples; @@ -214012,7 +230770,7 @@ index 000000000000..a384db5e7ac2 +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c new file mode 100644 -index 000000000000..53b62bd499a8 +index 000000000000..f789259d822b --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c @@ -0,0 +1,2757 @@ @@ -216350,7 +233108,7 @@ index 000000000000..53b62bd499a8 +int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) +{ + dwc_hc_t *hc = qh->channel; -+ struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ struct fiq_dma_channel *split_dma = hcd->fiq_dmab; + struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; + uint8_t *ptr = NULL; + int index = 0, len = 0; @@ -216370,7 +233128,7 @@ index 000000000000..53b62bd499a8 + + for (i = 0; i < st->dma_info.index; i++) { + len += st->dma_info.slot_len[i]; -+ dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]); ++ dwc_memcpy(ptr, &split_dma[num].index[i].buf[0], st->dma_info.slot_len[i]); + ptr += st->dma_info.slot_len[i]; + } + return len; @@ -232108,7 +248866,7 @@ index 000000000000..cdc9963176e5 +test_main(); +0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c -index b1e3fa54c639..1b31f629c657 100644 +index 54c47463c215..17f4a9fabee6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1400,6 +1400,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, @@ -232194,7 +248952,7 @@ index b1e3fa54c639..1b31f629c657 100644 erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c -index 44a749fdcafd..71ea283a4f23 100644 +index dbad516262ef..860e22f45d89 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -27,6 +27,8 @@ @@ -232206,7 +248964,7 @@ index 44a749fdcafd..71ea283a4f23 100644 /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 -@@ -290,6 +292,16 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) +@@ -295,6 +297,16 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) return 0; } @@ -232223,7 +248981,7 @@ index 44a749fdcafd..71ea283a4f23 100644 static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(dev); -@@ -479,8 +491,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) +@@ -490,8 +502,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == 0x3432) xhci->quirks |= XHCI_BROKEN_STREAMS; @@ -232241,7 +248999,7 @@ index 44a749fdcafd..71ea283a4f23 100644 if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c -index c91b6348aa30..82fddeb2ffe7 100644 +index 84cc0bf7066d..1c319e713b7f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -633,8 +633,11 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, @@ -232314,7 +249072,7 @@ index c91b6348aa30..82fddeb2ffe7 100644 } /* This function gets called from contexts where it cannot sleep */ -@@ -3596,6 +3628,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, +@@ -3641,6 +3673,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, return 1; } @@ -232363,7 +249121,7 @@ index c91b6348aa30..82fddeb2ffe7 100644 /* This is very similar to what ehci-q.c qtd_fill() does */ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) -@@ -3752,6 +3826,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, +@@ -3797,6 +3871,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } check_trb_math(urb, enqd_len); @@ -232372,7 +249130,7 @@ index c91b6348aa30..82fddeb2ffe7 100644 giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); return 0; -@@ -3887,6 +3963,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, +@@ -3932,6 +4008,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Event on completion */ field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); @@ -232382,10 +249140,10 @@ index c91b6348aa30..82fddeb2ffe7 100644 start_cycle, start_trb); return 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c -index 573b5784d1c3..6515eb72500a 100644 +index f005ce1f91ca..f2a81c18a28c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c -@@ -1486,6 +1486,109 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, +@@ -1496,6 +1496,109 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, return ret; } @@ -232495,7 +249253,7 @@ index 573b5784d1c3..6515eb72500a 100644 /* * non-error returns are a promise to giveback() the urb later * we drop ownership so next owner (or urb unlink) can get it -@@ -5316,6 +5419,7 @@ static const struct hc_driver xhci_hc_driver = { +@@ -5328,6 +5431,7 @@ static const struct hc_driver xhci_hc_driver = { .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, @@ -232504,10 +249262,10 @@ index 573b5784d1c3..6515eb72500a 100644 .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h -index d57471a9e643..56c8d5dc340f 100644 +index e8530f0ee27a..e79177e7bf43 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1679,8 +1679,9 @@ struct urb_priv { +@@ -1425,8 +1425,9 @@ struct urb_priv { * Each segment table entry is 4*32bits long. 1K seems like an ok size: * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. @@ -232519,9 +249277,9 @@ index d57471a9e643..56c8d5dc340f 100644 /* Poll every 60 seconds */ #define POLL_TIMEOUT 60 /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ -@@ -1914,6 +1915,11 @@ struct xhci_hcd { - #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45) - #define XHCI_ZHAOXIN_HOST BIT_ULL(46) +@@ -1662,6 +1663,11 @@ struct xhci_hcd { + #define XHCI_WRITE_64_HI_LO BIT_ULL(47) + #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) +/* Downstream VLI fixes */ +#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(56) @@ -232579,90 +249337,52 @@ index f72e1c3c59e9..e03cc5a394e5 100644 obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o -diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c -index 7115d7bb2a14..26ff4178cc16 100644 ---- a/drivers/video/backlight/lm3630a_bl.c -+++ b/drivers/video/backlight/lm3630a_bl.c -@@ -180,7 +180,7 @@ static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) +diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c +index 86e1cdc8e369..cfea80d4cfad 100644 +--- a/drivers/video/backlight/backlight.c ++++ b/drivers/video/backlight/backlight.c +@@ -285,6 +285,15 @@ static ssize_t max_brightness_show(struct device *dev, + } + static DEVICE_ATTR_RO(max_brightness); - pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false; - -- return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state); -+ return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state); ++static ssize_t display_name_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct backlight_device *bd = to_backlight_device(dev); ++ ++ return sprintf(buf, "%s\n", bd->props.display_name); ++} ++static DEVICE_ATTR_RO(display_name); ++ + static ssize_t actual_brightness_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -365,6 +374,7 @@ static struct attribute *bl_device_attrs[] = { + &dev_attr_max_brightness.attr, + &dev_attr_scale.attr, + &dev_attr_type.attr, ++ &dev_attr_display_name.attr, + NULL, + }; + ATTRIBUTE_GROUPS(bl_device); +@@ -662,6 +672,17 @@ static int of_parent_match(struct device *dev, const void *data) + return dev->parent && dev->parent->of_node == data; } - /* update and get brightness */ -diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c -index da1f124db69c..7075bfab59c4 100644 ---- a/drivers/video/backlight/lp855x_bl.c -+++ b/drivers/video/backlight/lp855x_bl.c -@@ -234,7 +234,7 @@ static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) - state.duty_cycle = div_u64(br * state.period, max_br); - state.enabled = state.duty_cycle; - -- return pwm_apply_state(lp->pwm, &state); -+ return pwm_apply_might_sleep(lp->pwm, &state); - } - - static int lp855x_bl_update_status(struct backlight_device *bl) -diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c -index 289bd9ce4d36..35c716e9043c 100644 ---- a/drivers/video/backlight/pwm_bl.c -+++ b/drivers/video/backlight/pwm_bl.c -@@ -103,7 +103,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) - pwm_get_state(pb->pwm, &state); - state.duty_cycle = compute_duty_cycle(pb, brightness, &state); - state.enabled = true; -- pwm_apply_state(pb->pwm, &state); -+ pwm_apply_might_sleep(pb->pwm, &state); - - pwm_backlight_power_on(pb); - } else { -@@ -120,7 +120,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) - * inactive output. - */ - state.enabled = !pb->power_supply && !pb->enable_gpio; -- pwm_apply_state(pb->pwm, &state); -+ pwm_apply_might_sleep(pb->pwm, &state); - } - - if (pb->notify_after) -@@ -528,7 +528,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) - if (!state.period && (data->pwm_period_ns > 0)) - state.period = data->pwm_period_ns; - -- ret = pwm_apply_state(pb->pwm, &state); -+ ret = pwm_apply_might_sleep(pb->pwm, &state); - if (ret) { - dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", - ret); -@@ -633,7 +633,7 @@ static void pwm_backlight_remove(struct platform_device *pdev) - pwm_get_state(pb->pwm, &state); - state.duty_cycle = 0; - state.enabled = false; -- pwm_apply_state(pb->pwm, &state); -+ pwm_apply_might_sleep(pb->pwm, &state); - - if (pb->exit) - pb->exit(&pdev->dev); -@@ -649,7 +649,7 @@ static void pwm_backlight_shutdown(struct platform_device *pdev) - pwm_get_state(pb->pwm, &state); - state.duty_cycle = 0; - state.enabled = false; -- pwm_apply_state(pb->pwm, &state); -+ pwm_apply_might_sleep(pb->pwm, &state); - } - - #ifdef CONFIG_PM_SLEEP -@@ -673,7 +673,7 @@ static int pwm_backlight_suspend(struct device *dev) - pwm_get_state(pb->pwm, &state); - state.duty_cycle = 0; - state.enabled = false; -- pwm_apply_state(pb->pwm, &state); -+ pwm_apply_might_sleep(pb->pwm, &state); - - if (pb->notify_after) - pb->notify_after(pb->dev, 0); ++int backlight_set_display_name(struct backlight_device *bd, const char *name) ++{ ++ if (!bd) ++ return -EINVAL; ++ ++ strscpy_pad(bd->props.display_name, name, sizeof(bd->props.display_name)); ++ ++ return 0; ++} ++EXPORT_SYMBOL(backlight_set_display_name); ++ + /** + * of_find_backlight_by_node() - find backlight device by device-tree node + * @node: device-tree node of the backlight device diff --git a/drivers/video/backlight/rpi_backlight.c b/drivers/video/backlight/rpi_backlight.c new file mode 100644 index 000000000000..14a0d9b03739 @@ -232789,7 +249509,7 @@ index 000000000000..14a0d9b03739 +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index 35b3ca2fb50a..9682b8711f71 100644 +index 2ada2b100c51..2dc48125d8f3 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -61,6 +61,21 @@ config FB_MACMODES @@ -232814,14 +249534,14 @@ index 35b3ca2fb50a..9682b8711f71 100644 config FB_GRVGA tristate "Aeroflex Gaisler framebuffer support" depends on FB && SPARC -@@ -1963,6 +1978,19 @@ config FB_LS2K500 - If you want to compile it as a module, say M here and read - . +@@ -1950,6 +1965,19 @@ config FB_SM712 + called sm712fb. If you want to compile it as a module, say M + here and read . +config FB_RPISENSE + tristate "Raspberry Pi Sense HAT framebuffer" -+ depends on FB -+ select MFD_RPISENSE_CORE ++ depends on FB && I2C ++ select MFD_SIMPLE_MFD_I2C + select FB_SYS_FOPS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA @@ -232831,9 +249551,9 @@ index 35b3ca2fb50a..9682b8711f71 100644 + help + This is the framebuffer driver for the Raspberry Pi Sense HAT + - source "drivers/video/fbdev/omap/Kconfig" - source "drivers/video/fbdev/omap2/Kconfig" - source "drivers/video/fbdev/mmp/Kconfig" + config FB_LS2K500 + tristate "Loongson LS2K500 frame buffer support" + depends on FB && PCI diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index d3fbb185daa3..e04b745ec510 100644 --- a/drivers/video/fbdev/Makefile @@ -234268,10 +250988,10 @@ index ee44a46a66be..e21782ba1ce2 100644 * @fb_info: frame buffer info structure diff --git a/drivers/video/fbdev/rpisense-fb.c b/drivers/video/fbdev/rpisense-fb.c new file mode 100644 -index 000000000000..22db39bf0f07 +index 000000000000..6db8195b8860 --- /dev/null +++ b/drivers/video/fbdev/rpisense-fb.c -@@ -0,0 +1,297 @@ +@@ -0,0 +1,296 @@ +/* + * Raspberry Pi Sense HAT framebuffer driver + * http://raspberrypi.org @@ -234297,16 +251017,14 @@ index 000000000000..22db39bf0f07 +#include +#include +#include ++#include + +#include -+#include + +static bool lowlight; +module_param(lowlight, bool, 0); +MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third"); + -+static struct rpisense *rpisense; -+ +struct rpisense_fb_param { + char __iomem *vmem; + u8 *vmem_work; @@ -234390,26 +251108,26 @@ index 000000000000..22db39bf0f07 +} + +static void rpisense_fb_deferred_io(struct fb_info *info, -+ struct list_head *pagelist) ++ struct list_head *pagelist) +{ + int i; + int j; + u8 *vmem_work = rpisense_fb_param.vmem_work; + u16 *mem = (u16 *)rpisense_fb_param.vmem; + u8 *gamma = rpisense_fb_param.gamma; ++ struct rpisense_fb *rpisense_fb = info->par; + -+ vmem_work[0] = 0; + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++) { -+ vmem_work[(j * 24) + i + 1] = ++ vmem_work[(j * 24) + i] = + gamma[(mem[(j * 8) + i] >> 11) & 0x1F]; -+ vmem_work[(j * 24) + (i + 8) + 1] = ++ vmem_work[(j * 24) + (i + 8)] = + gamma[(mem[(j * 8) + i] >> 6) & 0x1F]; -+ vmem_work[(j * 24) + (i + 16) + 1] = ++ vmem_work[(j * 24) + (i + 16)] = + gamma[(mem[(j * 8) + i]) & 0x1F]; + } + } -+ rpisense_block_write(rpisense, vmem_work, 193); ++ regmap_bulk_write(rpisense_fb->regmap, 0, vmem_work, 192); +} + +static struct fb_deferred_io rpisense_fb_defio = { @@ -234474,8 +251192,22 @@ index 000000000000..22db39bf0f07 + int ret = -ENOMEM; + struct rpisense_fb *rpisense_fb; + -+ rpisense = rpisense_get_dev(); -+ rpisense_fb = &rpisense->framebuffer; ++ info = framebuffer_alloc(sizeof(*rpisense_fb), &pdev->dev); ++ if (!info) { ++ dev_err(&pdev->dev, "Could not allocate framebuffer.\n"); ++ goto err_malloc; ++ } ++ ++ rpisense_fb = info->par; ++ platform_set_drvdata(pdev, rpisense_fb); ++ ++ rpisense_fb->pdev = pdev; ++ rpisense_fb->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!rpisense_fb->regmap) { ++ dev_err(&pdev->dev, ++ "unable to get sensehat regmap"); ++ return -ENODEV; ++ } + + rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize); + if (!rpisense_fb_param.vmem) @@ -234485,12 +251217,6 @@ index 000000000000..22db39bf0f07 + if (!rpisense_fb_param.vmem_work) + goto err_malloc; + -+ info = framebuffer_alloc(0, &pdev->dev); -+ if (!info) { -+ dev_err(&pdev->dev, "Could not allocate framebuffer.\n"); -+ goto err_malloc; -+ } -+ rpisense_fb->info = info; + + rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem; + rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize; @@ -234527,7 +251253,7 @@ index 000000000000..22db39bf0f07 + +static int rpisense_fb_remove(struct platform_device *pdev) +{ -+ struct rpisense_fb *rpisense_fb = &rpisense->framebuffer; ++ struct rpisense_fb *rpisense_fb = platform_get_drvdata(pdev); + struct fb_info *info = rpisense_fb->info; + + if (info) { @@ -234540,19 +251266,11 @@ index 000000000000..22db39bf0f07 + return 0; +} + -+#ifdef CONFIG_OF +static const struct of_device_id rpisense_fb_id[] = { -+ { .compatible = "rpi,rpi-sense-fb" }, ++ { .compatible = "raspberrypi,rpi-sense-fb" }, + { }, +}; +MODULE_DEVICE_TABLE(of, rpisense_fb_id); -+#endif -+ -+static struct platform_device_id rpisense_fb_device_id[] = { -+ { .name = "rpi-sense-fb" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id); + +static struct platform_driver rpisense_fb_driver = { + .probe = rpisense_fb_probe, @@ -234560,6 +251278,7 @@ index 000000000000..22db39bf0f07 + .driver = { + .name = "rpi-sense-fb", + .owner = THIS_MODULE, ++ .of_match_table = rpisense_fb_id, + }, +}; + @@ -234569,19 +251288,6 @@ index 000000000000..22db39bf0f07 +MODULE_AUTHOR("Serge Schneider "); +MODULE_LICENSE("GPL"); + -diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c -index 5ae48e36fccb..1a4f90ea7d5a 100644 ---- a/drivers/video/fbdev/ssd1307fb.c -+++ b/drivers/video/fbdev/ssd1307fb.c -@@ -347,7 +347,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) - - pwm_init_state(par->pwm, &pwmstate); - pwm_set_relative_duty_cycle(&pwmstate, 50, 100); -- pwm_apply_state(par->pwm, &pwmstate); -+ pwm_apply_might_sleep(par->pwm, &pwmstate); - - /* Enable the PWM */ - pwm_enable(par->pwm); diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm index 3c14e43b82fe..7626beb6a5bb 100644 --- a/drivers/video/logo/logo_linux_clut224.ppm @@ -237312,6 +254018,19 @@ index bb001c5d7f17..2ce96ba0ee39 100644 } static int bcm2835_wdt_probe(struct platform_device *pdev) +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 2a1aeab53ea4..1d4255d1999d 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -3929,6 +3929,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) + log->l_size = log->orig_file_size; + log->page_size = norm_file_page(t32, &log->l_size, + t32 == DefaultLogPageSize); ++ log->page_mask = log->page_size - 1; ++ log->page_bits = blksize_bits(log->page_size); + } + + if (log->page_size != t32 || diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index 6b5eec10c3db..5810aa8a9d87 100644 --- a/include/drm/drm_color_mgmt.h @@ -237345,7 +254064,7 @@ index d304ec8dd06b..5ba62fa5ef54 100644 * @DRM_MODE_TV_MODE_MAX: Number of analog TV output modes. * diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h -index c0aec0d4d664..4c44d3ed89b8 100644 +index 900262f4c234..48bfdd398fb0 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -113,29 +113,43 @@ struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); @@ -237461,10 +254180,10 @@ index 882a8a2aceba..744947bbeeb7 100644 KABI_RESERVE(3) diff --git a/include/dt-bindings/clock/rp1.h b/include/dt-bindings/clock/rp1.h new file mode 100644 -index 000000000000..27cbb6e130da +index 000000000000..1ebb25f16923 --- /dev/null +++ b/include/dt-bindings/clock/rp1.h -@@ -0,0 +1,56 @@ +@@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Raspberry Pi Ltd. @@ -237521,6 +254240,10 @@ index 000000000000..27cbb6e130da +/* Extra PLL output channels - RP1B0 only */ +#define RP1_PLL_VIDEO_PRI_PH 43 +#define RP1_PLL_AUDIO_TERN 44 ++ ++/* MIPI clocks managed by the DSI driver */ ++#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45 ++#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46 diff --git a/include/dt-bindings/gpio/gpio-fsm.h b/include/dt-bindings/gpio/gpio-fsm.h new file mode 100644 index 000000000000..eb40cfdc71df @@ -237789,6 +254512,45 @@ index 000000000000..80bbfd61b270 +#define RP1_DMA_PIO_CH3_RX 0x3f + +#endif +diff --git a/include/linux/backlight.h b/include/linux/backlight.h +index 614653e07e3a..24d35ad9a17f 100644 +--- a/include/linux/backlight.h ++++ b/include/linux/backlight.h +@@ -270,6 +270,13 @@ struct backlight_properties { + * @scale: The type of the brightness scale. + */ + enum backlight_scale scale; ++ ++#define BL_DISPLAY_NAME_LEN 32 ++ /** ++ * @display_name: Optional name that can be registered to associate a ++ * backlight device with a display device. ++ */ ++ char display_name[BL_DISPLAY_NAME_LEN]; + }; + + /** +@@ -478,12 +485,20 @@ of_find_backlight_by_node(struct device_node *node) + + #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) + struct backlight_device *devm_of_find_backlight(struct device *dev); ++int backlight_set_display_name(struct backlight_device *bd, const char *name); + #else + static inline struct backlight_device * + devm_of_find_backlight(struct device *dev) + { + return NULL; + } ++ ++static inline int backlight_set_display_name(struct backlight_device *bd, ++ const char *name) ++{ ++ return 0; ++} ++ + #endif + + #endif diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index c55810a43541..c5e6adc35cc9 100644 --- a/include/linux/brcmphy.h @@ -238243,8 +255005,28 @@ index 000000000000..3c7079237496 +#endif + +#endif /* _VC_MEM_H */ +diff --git a/include/linux/cma.h b/include/linux/cma.h +index b1c49616416b..08e95cce2a86 100644 +--- a/include/linux/cma.h ++++ b/include/linux/cma.h +@@ -57,6 +57,15 @@ extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data) + + extern void cma_reserve_pages_on_error(struct cma *cma); + ++#ifdef CONFIG_CMA ++extern int cma_check_range(u64 *start, u64 *end); ++#else ++static inline int cma_check_range(u64 *start, u64 *end) ++{ ++ return 0; ++} ++#endif ++ + #ifdef CONFIG_HYGON_CSV + extern int __init cma_alloc_areas(unsigned int max_cma_size); + #endif diff --git a/include/linux/fb.h b/include/linux/fb.h -index ab2a9f4163c7..703dd9cd4bd2 100644 +index 195513d589c2..146c0b309265 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -504,6 +504,7 @@ struct fb_info { @@ -238276,10 +255058,10 @@ index d6e38a500833..70c233440cdf 100644 int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq); diff --git a/include/linux/iommu.h b/include/linux/iommu.h -index 98acb1d50bd9..a0804d0f1f5e 100644 +index f7c3f7b839c0..22ab68ee58d6 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h -@@ -693,16 +693,20 @@ struct iommu_domain_ops { +@@ -697,15 +697,19 @@ struct iommu_domain_ops { int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev, ioasid_t pasid); @@ -238296,14 +255078,12 @@ index 98acb1d50bd9..a0804d0f1f5e 100644 void (*flush_iotlb_all)(struct iommu_domain *domain); - int (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, -- size_t size); + void (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, -+ size_t size); + size_t size); void (*iotlb_sync)(struct iommu_domain *domain, struct iommu_iotlb_gather *iotlb_gather); - int (*cache_invalidate_user)(struct iommu_domain *domain, diff --git a/include/linux/leds.h b/include/linux/leds.h -index aa16dc2a8230..9c7ad6eada2c 100644 +index d3056bc6f0a1..eafe6034550f 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -115,6 +115,9 @@ struct led_classdev { @@ -238316,65 +255096,12 @@ index aa16dc2a8230..9c7ad6eada2c 100644 /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; -diff --git a/include/linux/mfd/rpisense/core.h b/include/linux/mfd/rpisense/core.h -new file mode 100644 -index 000000000000..4856aa3c8b06 ---- /dev/null -+++ b/include/linux/mfd/rpisense/core.h -@@ -0,0 +1,47 @@ -+/* -+ * Raspberry Pi Sense HAT core driver -+ * http://raspberrypi.org -+ * -+ * Copyright (C) 2015 Raspberry Pi -+ * -+ * Author: Serge Schneider -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#ifndef __LINUX_MFD_RPISENSE_CORE_H_ -+#define __LINUX_MFD_RPISENSE_CORE_H_ -+ -+#include -+#include -+ -+/* -+ * Register values. -+ */ -+#define RPISENSE_FB 0x00 -+#define RPISENSE_WAI 0xF0 -+#define RPISENSE_VER 0xF1 -+#define RPISENSE_KEYS 0xF2 -+#define RPISENSE_EE_WP 0xF3 -+ -+#define RPISENSE_ID 's' -+ -+struct rpisense { -+ struct device *dev; -+ struct i2c_client *i2c_client; -+ -+ /* Client devices */ -+ struct rpisense_js joystick; -+ struct rpisense_fb framebuffer; -+}; -+ -+struct rpisense *rpisense_get_dev(void); -+s32 rpisense_reg_read(struct rpisense *rpisense, int reg); -+int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val); -+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count); -+ -+#endif diff --git a/include/linux/mfd/rpisense/framebuffer.h b/include/linux/mfd/rpisense/framebuffer.h new file mode 100644 -index 000000000000..2ba95d7eebaf +index 000000000000..621f24386bb0 --- /dev/null +++ b/include/linux/mfd/rpisense/framebuffer.h -@@ -0,0 +1,32 @@ +@@ -0,0 +1,35 @@ +/* + * Raspberry Pi Sense HAT framebuffer driver + * http://raspberrypi.org @@ -238393,6 +255120,8 @@ index 000000000000..2ba95d7eebaf +#ifndef __LINUX_RPISENSE_FB_H_ +#define __LINUX_RPISENSE_FB_H_ + ++#include ++ +#define SENSEFB_FBIO_IOC_MAGIC 0xF1 + +#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0) @@ -238402,8 +255131,9 @@ index 000000000000..2ba95d7eebaf +struct rpisense; + +struct rpisense_fb { -+ struct platform_device *pdev; + struct fb_info *info; ++ struct platform_device *pdev; ++ struct regmap *regmap; +}; + +#endif @@ -238468,7 +255198,7 @@ index 517288da19fd..626c450d71f4 100644 #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A) #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h -index 0fe6576eb81f..155f90ad4ead 100644 +index 0fe6576eb81f..52e46062d19a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -299,6 +299,7 @@ struct mmc_card { @@ -238487,6 +255217,14 @@ index 0fe6576eb81f..155f90ad4ead 100644 unsigned int sdio_funcs; /* number of SDIO functions */ atomic_t sdio_funcs_probed; /* number of probed SDIO funcs */ +@@ -344,6 +346,7 @@ struct mmc_card { + unsigned int nr_parts; + + struct workqueue_struct *complete_wq; /* Private workqueue */ ++ unsigned int max_posted_writes; /* command queue posted write limit */ + KABI_RESERVE(0) + KABI_RESERVE(1) + KABI_RESERVE(2) diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h index 6727576a8755..52f2c7a90a13 100644 --- a/include/linux/mmc/sd.h @@ -238518,7 +255256,7 @@ index 6727576a8755..52f2c7a90a13 100644 * SCR field definitions */ diff --git a/include/linux/module.h b/include/linux/module.h -index 4db2878d9e42..bf726cea4035 100644 +index 990f9d66d2f1..74a8b16b3bcf 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -513,7 +513,7 @@ struct module { @@ -238529,7 +255267,7 @@ index 4db2878d9e42..bf726cea4035 100644 +#if 1 unsigned int btf_data_size; void *btf_data; - #endif + #else diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h new file mode 100644 index 000000000000..6ca874d332a8 @@ -238680,54 +255418,9 @@ index 000000000000..6ca874d332a8 + +#endif /* _PLAT_BCM2708_DMA_H */ diff --git a/include/linux/pwm.h b/include/linux/pwm.h -index fe0f38ce1bde..4bfbd25ade06 100644 +index 63426d8255e4..4bfbd25ade06 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h -@@ -95,8 +95,8 @@ struct pwm_device { - * @state: state to fill with the current PWM state - * - * The returned PWM state represents the state that was applied by a previous call to -- * pwm_apply_state(). Drivers may have to slightly tweak that state before programming it to -- * hardware. If pwm_apply_state() was never called, this returns either the current hardware -+ * pwm_apply_might_sleep(). Drivers may have to slightly tweak that state before programming it to -+ * hardware. If pwm_apply_might_sleep() was never called, this returns either the current hardware - * state (if supported) or the default settings. - */ - static inline void pwm_get_state(const struct pwm_device *pwm, -@@ -160,20 +160,20 @@ static inline void pwm_get_args(const struct pwm_device *pwm, - } - - /** -- * pwm_init_state() - prepare a new state to be applied with pwm_apply_state() -+ * pwm_init_state() - prepare a new state to be applied with pwm_apply_might_sleep() - * @pwm: PWM device - * @state: state to fill with the prepared PWM state - * - * This functions prepares a state that can later be tweaked and applied -- * to the PWM device with pwm_apply_state(). This is a convenient function -+ * to the PWM device with pwm_apply_might_sleep(). This is a convenient function - * that first retrieves the current PWM state and the replaces the period - * and polarity fields with the reference values defined in pwm->args. - * Once the function returns, you can adjust the ->enabled and ->duty_cycle -- * fields according to your needs before calling pwm_apply_state(). -+ * fields according to your needs before calling pwm_apply_might_sleep(). - * - * ->duty_cycle is initially set to zero to avoid cases where the current - * ->duty_cycle value exceed the pwm_args->period one, which would trigger -- * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle -+ * an error if the user calls pwm_apply_might_sleep() without adjusting ->duty_cycle - * first. - */ - static inline void pwm_init_state(const struct pwm_device *pwm, -@@ -229,7 +229,7 @@ pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale) - * - * pwm_init_state(pwm, &state); - * pwm_set_relative_duty_cycle(&state, 50, 100); -- * pwm_apply_state(pwm, &state); -+ * pwm_apply_might_sleep(pwm, &state); - * - * This functions returns -EINVAL if @duty_cycle and/or @scale are - * inconsistent (@scale == 0 or @duty_cycle > @scale). @@ -289,6 +289,7 @@ struct pwm_ops { * @npwm: number of PWMs controlled by this chip * @of_xlate: request a PWM device given a device tree PWM specifier @@ -238744,42 +255437,18 @@ index fe0f38ce1bde..4bfbd25ade06 100644 /* only used internally by the PWM framework */ struct list_head list; -@@ -309,7 +311,8 @@ struct pwm_chip { - +@@ -310,6 +312,7 @@ struct pwm_chip { #if IS_ENABLED(CONFIG_PWM) /* PWM user APIs */ --int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state); -+int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state); + int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state); +int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state); int pwm_adjust_config(struct pwm_device *pwm); /** -@@ -337,7 +340,7 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns, - - state.duty_cycle = duty_ns; - state.period = period_ns; -- return pwm_apply_state(pwm, &state); -+ return pwm_apply_might_sleep(pwm, &state); +@@ -380,6 +383,17 @@ static inline void pwm_disable(struct pwm_device *pwm) + pwm_apply_might_sleep(pwm, &state); } - /** -@@ -358,7 +361,7 @@ static inline int pwm_enable(struct pwm_device *pwm) - return 0; - - state.enabled = true; -- return pwm_apply_state(pwm, &state); -+ return pwm_apply_might_sleep(pwm, &state); - } - - /** -@@ -377,7 +380,18 @@ static inline void pwm_disable(struct pwm_device *pwm) - return; - - state.enabled = false; -- pwm_apply_state(pwm, &state); -+ pwm_apply_might_sleep(pwm, &state); -+} -+ +/** + * pwm_might_sleep() - is pwm_apply_atomic() supported? + * @pwm: PWM device @@ -238789,22 +255458,22 @@ index fe0f38ce1bde..4bfbd25ade06 100644 +static inline bool pwm_might_sleep(struct pwm_device *pwm) +{ + return !pwm->chip->atomic; - } - ++} ++ /* PWM provider APIs */ + int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, + unsigned long timeout); @@ -408,16 +422,27 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id); #else --static inline int pwm_apply_state(struct pwm_device *pwm, -- const struct pwm_state *state) +static inline bool pwm_might_sleep(struct pwm_device *pwm) +{ + return true; +} + -+static inline int pwm_apply_might_sleep(struct pwm_device *pwm, -+ const struct pwm_state *state) + static inline int pwm_apply_might_sleep(struct pwm_device *pwm, + const struct pwm_state *state) { might_sleep(); - return -ENOTSUPP; @@ -238824,15 +255493,6 @@ index fe0f38ce1bde..4bfbd25ade06 100644 } static inline int pwm_config(struct pwm_device *pwm, int duty_ns, -@@ -536,7 +561,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) - state.period = pwm->args.period; - state.usage_power = false; - -- pwm_apply_state(pwm, &state); -+ pwm_apply_might_sleep(pwm, &state); - } - - struct pwm_lookup { diff --git a/include/linux/rp1_platform.h b/include/linux/rp1_platform.h new file mode 100644 index 000000000000..f805dbe1ed9b @@ -239705,22 +256365,1210 @@ index a03c543cb072..7fbeb5a95f45 100644 +#define MEDIA_BUS_FMT_SENSOR_DATA 0x7002 + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ +diff --git a/include/uapi/linux/media/raspberrypi/pisp_be_config.h b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +new file mode 100644 +index 000000000000..cbeb714f4d61 +--- /dev/null ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -0,0 +1,968 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ ++/* ++ * PiSP Back End configuration definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd ++ * ++ */ ++#ifndef _UAPI_PISP_BE_CONFIG_H_ ++#define _UAPI_PISP_BE_CONFIG_H_ ++ ++#include ++ ++#include "pisp_common.h" ++ ++/* byte alignment for inputs */ ++#define PISP_BACK_END_INPUT_ALIGN 4u ++/* alignment for compressed inputs */ ++#define PISP_BACK_END_COMPRESSED_ALIGN 8u ++/* minimum required byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u ++/* preferred byte alignment for outputs */ ++#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u ++ ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_WIDTH 16u ++/* minimum allowed tile width anywhere in the pipeline */ ++#define PISP_BACK_END_MIN_TILE_HEIGHT 16u ++ ++#define PISP_BACK_END_NUM_OUTPUTS 2 ++#define PISP_BACK_END_HOG_OUTPUT 1 ++ ++#define PISP_BACK_END_NUM_TILES 64 ++ ++enum pisp_be_bayer_enable { ++ PISP_BE_BAYER_ENABLE_INPUT = 0x000001, ++ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002, ++ PISP_BE_BAYER_ENABLE_DPC = 0x000004, ++ PISP_BE_BAYER_ENABLE_GEQ = 0x000008, ++ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010, ++ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020, ++ PISP_BE_BAYER_ENABLE_TDN = 0x000040, ++ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080, ++ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100, ++ PISP_BE_BAYER_ENABLE_SDN = 0x000200, ++ PISP_BE_BAYER_ENABLE_BLC = 0x000400, ++ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800, ++ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000, ++ PISP_BE_BAYER_ENABLE_STITCH = 0x002000, ++ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000, ++ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000, ++ PISP_BE_BAYER_ENABLE_WBG = 0x010000, ++ PISP_BE_BAYER_ENABLE_CDN = 0x020000, ++ PISP_BE_BAYER_ENABLE_LSC = 0x040000, ++ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000, ++ PISP_BE_BAYER_ENABLE_CAC = 0x100000, ++ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000, ++ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000, ++}; ++ ++enum pisp_be_rgb_enable { ++ PISP_BE_RGB_ENABLE_INPUT = 0x000001, ++ PISP_BE_RGB_ENABLE_CCM = 0x000002, ++ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004, ++ PISP_BE_RGB_ENABLE_YCBCR = 0x000008, ++ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010, ++ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020, ++ /* Preferred colours would occupy 0x000040 */ ++ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080, ++ PISP_BE_RGB_ENABLE_GAMMA = 0x000100, ++ PISP_BE_RGB_ENABLE_CSC0 = 0x000200, ++ PISP_BE_RGB_ENABLE_CSC1 = 0x000400, ++ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000, ++ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000, ++ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000, ++ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000, ++ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000, ++ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000, ++ PISP_BE_RGB_ENABLE_HOG = 0x200000 ++}; ++ ++#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i)) ++#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i)) ++#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i)) ++#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i)) ++ ++/* ++ * We use the enable flags to show when blocks are "dirty", but we need some ++ * extra ones too. ++ */ ++enum pisp_be_dirty { ++ PISP_BE_DIRTY_GLOBAL = 0x0001, ++ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002, ++ PISP_BE_DIRTY_CROP = 0x0004 ++}; ++ ++/** ++ * struct pisp_be_global_config - PiSP global enable bitmaps ++ * @bayer_enables: Bayer input enable flags ++ * @rgb_enables: RGB output enable flags ++ * @bayer_order: Bayer input format ordering ++ * @pad: Padding bytes ++ */ ++struct pisp_be_global_config { ++ __u32 bayer_enables; ++ __u32 rgb_enables; ++ __u8 bayer_order; ++ __u8 pad[3]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_input_buffer_config - PiSP Back End input buffer ++ * @addr: Input buffer address ++ */ ++struct pisp_be_input_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */ ++ __u32 addr[3][2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_dpc_config - PiSP Back End DPC config ++ * ++ * Defective Pixel Correction configuration ++ * ++ * @coeff_level: Coefficient for the darkest neighbouring pixel value ++ * @coeff_range: Coefficient for the range of pixels for this Bayer channel ++ * @pad: Padding byte ++ * @flags: DPC configuration flags ++ */ ++struct pisp_be_dpc_config { ++ __u8 coeff_level; ++ __u8 coeff_range; ++ __u8 pad; ++#define PISP_BE_DPC_FLAG_FOLDBACK 1 ++ __u8 flags; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_geq_config - PiSP Back End GEQ config ++ * ++ * Green Equalisation configuration ++ * ++ * @offset: Offset value for threshold calculation ++ * @slope_sharper: Slope/Sharper configuration ++ * @min: Minimum value the threshold may have ++ * @max: Maximum value the threshold may have ++ */ ++struct pisp_be_geq_config { ++ __u16 offset; ++#define PISP_BE_GEQ_SHARPER (1U << 15) ++#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1) ++ /* top bit is the "sharper" flag, slope value is bottom 10 bits */ ++ __u16 slope_sharper; ++ __u16 min; ++ __u16 max; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_tdn_input_buffer_config - PiSP Back End TDN input buffer ++ * @addr: TDN input buffer address ++ */ ++struct pisp_be_tdn_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ __u32 addr[2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_tdn_config - PiSP Back End TDN config ++ * ++ * Temporal Denoise configuration ++ * ++ * @black_level: Black level value subtracted from pixels ++ * @ratio: Multiplier for the LTA input frame ++ * @noise_constant: Constant offset value used in noise estimation ++ * @noise_slope: Noise estimation multiplier ++ * @threshold: Threshold for TDN operations ++ * @reset: Disable TDN operations ++ * @pad: Padding byte ++ */ ++struct pisp_be_tdn_config { ++ __u16 black_level; ++ __u16 ratio; ++ __u16 noise_constant; ++ __u16 noise_slope; ++ __u16 threshold; ++ __u8 reset; ++ __u8 pad; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_tdn_output_buffer_config - PiSP Back End TDN output buffer ++ * @addr: TDN output buffer address ++ */ ++struct pisp_be_tdn_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ __u32 addr[2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_sdn_config - PiSP Back End SDN config ++ * ++ * Spatial Denoise configuration ++ * ++ * @black_level: Black level subtracted from pixel for noise estimation ++ * @leakage: Proportion of the original undenoised value to mix in ++ * denoised output ++ * @pad: Padding byte ++ * @noise_constant: Noise constant used for noise estimation ++ * @noise_slope: Noise slope value used for noise estimation ++ * @noise_constant2: Second noise constant used for noise estimation ++ * @noise_slope2: Second slope value used for noise estimation ++ */ ++struct pisp_be_sdn_config { ++ __u16 black_level; ++ __u8 leakage; ++ __u8 pad; ++ __u16 noise_constant; ++ __u16 noise_slope; ++ __u16 noise_constant2; ++ __u16 noise_slope2; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_stitch_input_buffer_config - PiSP Back End Stitch input ++ * @addr: Stitch input buffer address ++ */ ++struct pisp_be_stitch_input_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ __u32 addr[2]; ++} __attribute__((packed)); ++ ++#define PISP_BE_STITCH_STREAMING_LONG 0x8000 ++#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff ++ ++/** ++ * struct pisp_be_stitch_config - PiSP Back End Stitch config ++ * ++ * Stitch block configuration ++ * ++ * @threshold_lo: Low threshold value ++ * @threshold_diff_power: Low and high threshold difference ++ * @pad: Padding bytes ++ * @exposure_ratio: Multiplier to convert long exposure pixels into ++ * short exposure pixels ++ * @motion_threshold_256: Motion threshold above which short exposure ++ * pixels are used ++ * @motion_threshold_recip: Reciprocal of motion_threshold_256 value ++ */ ++struct pisp_be_stitch_config { ++ __u16 threshold_lo; ++ __u8 threshold_diff_power; ++ __u8 pad; ++ ++ /* top bit indicates whether streaming input is the long exposure */ ++ __u16 exposure_ratio; ++ ++ __u8 motion_threshold_256; ++ __u8 motion_threshold_recip; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_stitch_output_buffer_config - PiSP Back End Stitch output ++ * @addr: Stitch input buffer address ++ */ ++struct pisp_be_stitch_output_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ __u32 addr[2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_cdn_config - PiSP Back End CDN config ++ * ++ * Colour Denoise configuration ++ * ++ * @thresh: Constant for noise estimation ++ * @iir_strength: Relative strength of the IIR part of the filter ++ * @g_adjust: Proportion of the change assigned to the G channel ++ */ ++struct pisp_be_cdn_config { ++ __u16 thresh; ++ __u8 iir_strength; ++ __u8 g_adjust; ++} __attribute__((packed)); ++ ++#define PISP_BE_LSC_LOG_GRID_SIZE 5 ++#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE) ++#define PISP_BE_LSC_STEP_PRECISION 18 ++ ++/** ++ * struct pisp_be_lsc_config - PiSP Back End LSC config ++ * ++ * Lens Shading Correction configuration ++ * ++ * @grid_step_x: Reciprocal of cell size width ++ * @grid_step_y: Reciprocal of cell size height ++ * @lut_packed: Jointly-coded RGB gains for each LSC grid ++ */ ++struct pisp_be_lsc_config { ++ /* (1<<18) / grid_cell_width */ ++ __u16 grid_step_x; ++ /* (1<<18) / grid_cell_height */ ++ __u16 grid_step_y; ++ /* RGB gains jointly encoded in 32 bits */ ++#define PISP_BE_LSC_LUT_SIZE (PISP_BE_LSC_GRID_SIZE + 1) ++ __u32 lut_packed[PISP_BE_LSC_LUT_SIZE][PISP_BE_LSC_LUT_SIZE]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_lsc_extra - PiSP Back End LSC Extra config ++ * @offset_x: Horizontal offset into the LSC table of this tile ++ * @offset_y: Vertical offset into the LSC table of this tile ++ */ ++struct pisp_be_lsc_extra { ++ __u16 offset_x; ++ __u16 offset_y; ++} __attribute__((packed)); ++ ++#define PISP_BE_CAC_LOG_GRID_SIZE 3 ++#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE) ++#define PISP_BE_CAC_STEP_PRECISION 20 ++ ++/** ++ * struct pisp_be_cac_config - PiSP Back End CAC config ++ * ++ * Chromatic Aberration Correction config ++ * ++ * @grid_step_x: Reciprocal of cell size width ++ * @grid_step_y: Reciprocal of cell size height ++ * @lut: Pixel shift for the CAC grid ++ */ ++struct pisp_be_cac_config { ++ /* (1<<20) / grid_cell_width */ ++ __u16 grid_step_x; ++ /* (1<<20) / grid_cell_height */ ++ __u16 grid_step_y; ++ /* [gridy][gridx][rb][xy] */ ++#define PISP_BE_CAC_LUT_SIZE (PISP_BE_CAC_GRID_SIZE + 1) ++ __s8 lut[PISP_BE_CAC_LUT_SIZE][PISP_BE_CAC_LUT_SIZE][2][2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_cac_extra - PiSP Back End CAC extra config ++ * @offset_x: Horizontal offset into the CAC table of this tile ++ * @offset_y: Horizontal offset into the CAC table of this tile ++ */ ++struct pisp_be_cac_extra { ++ __u16 offset_x; ++ __u16 offset_y; ++} __attribute__((packed)); ++ ++#define PISP_BE_DEBIN_NUM_COEFFS 4 ++ ++/** ++ * struct pisp_be_debin_config - PiSP Back End Debin config ++ * ++ * Debinning configuration ++ * ++ * @coeffs: Filter coefficients for debinning ++ * @h_enable: Horizontal debinning enable ++ * @v_enable: Vertical debinning enable ++ * @pad: Padding bytes ++ */ ++struct pisp_be_debin_config { ++ __s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS]; ++ __s8 h_enable; ++ __s8 v_enable; ++ __s8 pad[2]; ++} __attribute__((packed)); ++ ++#define PISP_BE_TONEMAP_LUT_SIZE 64 ++ ++/** ++ * struct pisp_be_tonemap_config - PiSP Back End Tonemap config ++ * ++ * Tonemapping configuration ++ * ++ * @detail_constant: Constant value for threshold calculation ++ * @detail_slope: Slope value for threshold calculation ++ * @iir_strength: Relative strength of the IIR fiter ++ * @strength: Strength factor ++ * @lut: Look-up table for tonemap curve ++ */ ++struct pisp_be_tonemap_config { ++ __u16 detail_constant; ++ __u16 detail_slope; ++ __u16 iir_strength; ++ __u16 strength; ++ __u32 lut[PISP_BE_TONEMAP_LUT_SIZE]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_demosaic_config - PiSP Back End Demosaic config ++ * ++ * Demosaic configuration ++ * ++ * @sharper: Use other Bayer channels to increase sharpness ++ * @fc_mode: Built-in false colour suppression mode ++ * @pad: Padding bytes ++ */ ++struct pisp_be_demosaic_config { ++ __u8 sharper; ++ __u8 fc_mode; ++ __u8 pad[2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_ccm_config - PiSP Back End CCM config ++ * ++ * Colour Correction Matrix configuration ++ * ++ * @coeffs: Matrix coefficients ++ * @pad: Padding bytes ++ * @offsets: Offsets triplet ++ */ ++struct pisp_be_ccm_config { ++ __s16 coeffs[9]; ++ __u8 pad[2]; ++ __s32 offsets[3]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_sat_control_config - PiSP Back End SAT config ++ * ++ * Saturation Control configuration ++ * ++ * @shift_r: Left shift for Red colour channel ++ * @shift_g: Left shift for Green colour channel ++ * @shift_b: Left shift for Blue colour channel ++ * @pad: Padding byte ++ */ ++struct pisp_be_sat_control_config { ++ __u8 shift_r; ++ __u8 shift_g; ++ __u8 shift_b; ++ __u8 pad; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_false_colour_config - PiSP Back End False Colour config ++ * ++ * False Colour configuration ++ * ++ * @distance: Distance of neighbouring pixels, either 1 or 2 ++ * @pad: Padding bytes ++ */ ++struct pisp_be_false_colour_config { ++ __u8 distance; ++ __u8 pad[3]; ++} __attribute__((packed)); ++ ++#define PISP_BE_SHARPEN_SIZE 5 ++#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9 ++ ++/** ++ * struct pisp_be_sharpen_config - PiSP Back End Sharpening config ++ * ++ * Sharpening configuration ++ * ++ * @kernel0: Coefficient for filter 0 ++ * @pad0: Padding byte ++ * @kernel1: Coefficient for filter 1 ++ * @pad1: Padding byte ++ * @kernel2: Coefficient for filter 2 ++ * @pad2: Padding byte ++ * @kernel3: Coefficient for filter 3 ++ * @pad3: Padding byte ++ * @kernel4: Coefficient for filter 4 ++ * @pad4: Padding byte ++ * @threshold_offset0: Offset for filter 0 response calculation ++ * @threshold_slope0: Slope multiplier for the filter 0 response calculation ++ * @scale0: Scale factor for filter 0 response calculation ++ * @pad5: Padding byte ++ * @threshold_offset1: Offset for filter 0 response calculation ++ * @threshold_slope1: Slope multiplier for the filter 0 response calculation ++ * @scale1: Scale factor for filter 0 response calculation ++ * @pad6: Padding byte ++ * @threshold_offset2: Offset for filter 0 response calculation ++ * @threshold_slope2: Slope multiplier for the filter 0 response calculation ++ * @scale2: Scale factor for filter 0 response calculation ++ * @pad7: Padding byte ++ * @threshold_offset3: Offset for filter 0 response calculation ++ * @threshold_slope3: Slope multiplier for the filter 0 response calculation ++ * @scale3: Scale factor for filter 0 response calculation ++ * @pad8: Padding byte ++ * @threshold_offset4: Offset for filter 0 response calculation ++ * @threshold_slope4: Slope multiplier for the filter 0 response calculation ++ * @scale4: Scale factor for filter 0 response calculation ++ * @pad9: Padding byte ++ * @positive_strength: Factor to scale the positive sharpening strength ++ * @positive_pre_limit: Maximum allowed possible positive sharpening value ++ * @positive_func: Gain factor applied to positive sharpening response ++ * @positive_limit: Final gain factor applied to positive sharpening ++ * @negative_strength: Factor to scale the negative sharpening strength ++ * @negative_pre_limit: Maximum allowed possible negative sharpening value ++ * @negative_func: Gain factor applied to negative sharpening response ++ * @negative_limit: Final gain factor applied to negative sharpening ++ * @enables: Filter enable mask ++ * @white: White output pixel filter mask ++ * @black: Black output pixel filter mask ++ * @grey: Grey output pixel filter mask ++ */ ++struct pisp_be_sharpen_config { ++ __s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ __s8 pad0[3]; ++ __s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ __s8 pad1[3]; ++ __s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ __s8 pad2[3]; ++ __s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ __s8 pad3[3]; ++ __s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE]; ++ __s8 pad4[3]; ++ __u16 threshold_offset0; ++ __u16 threshold_slope0; ++ __u16 scale0; ++ __u16 pad5; ++ __u16 threshold_offset1; ++ __u16 threshold_slope1; ++ __u16 scale1; ++ __u16 pad6; ++ __u16 threshold_offset2; ++ __u16 threshold_slope2; ++ __u16 scale2; ++ __u16 pad7; ++ __u16 threshold_offset3; ++ __u16 threshold_slope3; ++ __u16 scale3; ++ __u16 pad8; ++ __u16 threshold_offset4; ++ __u16 threshold_slope4; ++ __u16 scale4; ++ __u16 pad9; ++ __u16 positive_strength; ++ __u16 positive_pre_limit; ++ __u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; ++ __u16 positive_limit; ++ __u16 negative_strength; ++ __u16 negative_pre_limit; ++ __u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS]; ++ __u16 negative_limit; ++ __u8 enables; ++ __u8 white; ++ __u8 black; ++ __u8 grey; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_sh_fc_combine_config - PiSP Back End Sharpening and ++ * False Colour config ++ * ++ * Sharpening and False Colour configuration ++ * ++ * @y_factor: Control amount of desaturation of pixels being darkened ++ * @c1_factor: Control amount of brightening of a pixel for the Cb ++ * channel ++ * @c2_factor: Control amount of brightening of a pixel for the Cr ++ * channel ++ * @pad: Padding byte ++ */ ++struct pisp_be_sh_fc_combine_config { ++ __u8 y_factor; ++ __u8 c1_factor; ++ __u8 c2_factor; ++ __u8 pad; ++} __attribute__((packed)); ++ ++#define PISP_BE_GAMMA_LUT_SIZE 64 ++ ++/** ++ * struct pisp_be_gamma_config - PiSP Back End Gamma configuration ++ * @lut: Gamma curve look-up table ++ */ ++struct pisp_be_gamma_config { ++ __u32 lut[PISP_BE_GAMMA_LUT_SIZE]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_crop_config - PiSP Back End Crop config ++ * ++ * Crop configuration ++ * ++ * @offset_x: Number of pixels cropped from the left of the tile ++ * @offset_y: Number of pixels cropped from the top of the tile ++ * @width: Width of the cropped tile output ++ * @height: Height of the cropped tile output ++ */ ++struct pisp_be_crop_config { ++ __u16 offset_x, offset_y; ++ __u16 width, height; ++} __attribute__((packed)); ++ ++#define PISP_BE_RESAMPLE_FILTER_SIZE 96 ++ ++/** ++ * struct pisp_be_resample_config - PiSP Back End Resampling config ++ * ++ * Resample configuration ++ * ++ * @scale_factor_h: Horizontal scale factor ++ * @scale_factor_v: Vertical scale factor ++ * @coef: Resample coefficients ++ */ ++struct pisp_be_resample_config { ++ __u16 scale_factor_h, scale_factor_v; ++ __s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_resample_extra - PiSP Back End Resample config ++ * ++ * Resample configuration ++ * ++ * @scaled_width: Width in pixels of the scaled output ++ * @scaled_height: Height in pixels of the scaled output ++ * @initial_phase_h: Initial horizontal phase ++ * @initial_phase_v: Initial vertical phase ++ */ ++struct pisp_be_resample_extra { ++ __u16 scaled_width; ++ __u16 scaled_height; ++ __s16 initial_phase_h[3]; ++ __s16 initial_phase_v[3]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_downscale_config - PiSP Back End Downscale config ++ * ++ * Downscale configuration ++ * ++ * @scale_factor_h: Horizontal scale factor ++ * @scale_factor_v: Vertical scale factor ++ * @scale_recip_h: Horizontal reciprocal factor ++ * @scale_recip_v: Vertical reciprocal factor ++ */ ++struct pisp_be_downscale_config { ++ __u16 scale_factor_h; ++ __u16 scale_factor_v; ++ __u16 scale_recip_h; ++ __u16 scale_recip_v; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_downscale_extra - PiSP Back End Downscale Extra config ++ * @scaled_width: Scaled image width ++ * @scaled_height: Scaled image height ++ */ ++struct pisp_be_downscale_extra { ++ __u16 scaled_width; ++ __u16 scaled_height; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_hog_config - PiSP Back End HOG config ++ * ++ * Histogram of Oriented Gradients configuration ++ * ++ * @compute_signed: Set 0 for unsigned gradients, 1 for signed ++ * @channel_mix: Channels proportions to use ++ * @stride: Stride in bytes between blocks directly below ++ */ ++struct pisp_be_hog_config { ++ __u8 compute_signed; ++ __u8 channel_mix[3]; ++ __u32 stride; ++} __attribute__((packed)); ++ ++struct pisp_be_axi_config { ++ __u8 r_qos; /* Read QoS */ ++ __u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */ ++ __u8 w_qos; /* Write QoS */ ++ __u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */ ++} __attribute__((packed)); ++ ++/** ++ * enum pisp_be_transform - PiSP Back End Transform flags ++ * @PISP_BE_TRANSFORM_NONE: No transform ++ * @PISP_BE_TRANSFORM_HFLIP: Horizontal flip ++ * @PISP_BE_TRANSFORM_VFLIP: Vertical flip ++ * @PISP_BE_TRANSFORM_ROT180: 180 degress rotation ++ */ ++enum pisp_be_transform { ++ PISP_BE_TRANSFORM_NONE = 0x0, ++ PISP_BE_TRANSFORM_HFLIP = 0x1, ++ PISP_BE_TRANSFORM_VFLIP = 0x2, ++ PISP_BE_TRANSFORM_ROT180 = ++ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP) ++}; ++ ++struct pisp_be_output_format_config { ++ struct pisp_image_format_config image; ++ __u8 transform; ++ __u8 pad[3]; ++ __u16 lo; ++ __u16 hi; ++ __u16 lo2; ++ __u16 hi2; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_output_buffer_config - PiSP Back End Output buffer ++ * @addr: Output buffer address ++ */ ++struct pisp_be_output_buffer_config { ++ /* low 32 bits followed by high 32 bits (for each of 3 planes) */ ++ __u32 addr[3][2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_hog_buffer_config - PiSP Back End HOG buffer ++ * @addr: HOG buffer address ++ */ ++struct pisp_be_hog_buffer_config { ++ /* low 32 bits followed by high 32 bits */ ++ __u32 addr[2]; ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration ++ * ++ * @input_buffer: Input buffer addresses ++ * @tdn_input_buffer: TDN input buffer addresses ++ * @stitch_input_buffer: Stitch input buffer addresses ++ * @tdn_output_buffer: TDN output buffer addresses ++ * @stitch_output_buffer: Stitch output buffer addresses ++ * @output_buffer: Output buffers addresses ++ * @hog_buffer: HOG buffer addresses ++ * @global: Global PiSP configuration ++ * @input_format: Input image format ++ * @decompress: Decompress configuration ++ * @dpc: Defective Pixel Correction configuration ++ * @geq: Green Equalisation configuration ++ * @tdn_input_format: Temporal Denoise input format ++ * @tdn_decompress: Temporal Denoise decompress configuration ++ * @tdn: Temporal Denoise configuration ++ * @tdn_compress: Temporal Denoise compress configuration ++ * @tdn_output_format: Temporal Denoise output format ++ * @sdn: Spatial Denoise configuration ++ * @blc: Black Level Correction configuration ++ * @stitch_compress: Stitch compress configuration ++ * @stitch_output_format: Stitch output format ++ * @stitch_input_format: Stitch input format ++ * @stitch_decompress: Stitch decompress configuration ++ * @stitch: Stitch configuration ++ * @lsc: Lens Shading Correction configuration ++ * @wbg: White Balance Gain configuration ++ * @cdn: Colour Denoise configuration ++ * @cac: Colour Aberration Correction configuration ++ * @debin: Debinning configuration ++ * @tonemap: Tonemapping configuration ++ * @demosaic: Demosaicing configuration ++ * @ccm: Colour Correction Matrix configuration ++ * @sat_control: Saturation Control configuration ++ * @ycbcr: YCbCr colour correction configuration ++ * @sharpen: Sharpening configuration ++ * @false_colour: False colour correction ++ * @sh_fc_combine: Sharpening and False Colour correction ++ * @ycbcr_inverse: Inverse YCbCr colour correction ++ * @gamma: Gamma curve configuration ++ * @csc: Color Space Conversion configuration ++ * @downscale: Downscale configuration ++ * @resample: Resampling configuration ++ * @output_format: Output format configuration ++ * @hog: HOG configuration ++ * @axi: AXI bus configuration ++ * @lsc_extra: LSC extra info ++ * @cac_extra: CAC extra info ++ * @downscale_extra: Downscaler extra info ++ * @resample_extra: Resample extra info ++ * @crop: Crop configuration ++ * @hog_format: HOG format info ++ * @dirty_flags_bayer: Bayer enable dirty flags ++ * (:c:type:`pisp_be_bayer_enable`) ++ * @dirty_flags_rgb: RGB enable dirty flags ++ * (:c:type:`pisp_be_rgb_enable`) ++ * @dirty_flags_extra: Extra dirty flags ++ */ ++struct pisp_be_config { ++ /* I/O configuration: */ ++ struct pisp_be_input_buffer_config input_buffer; ++ struct pisp_be_tdn_input_buffer_config tdn_input_buffer; ++ struct pisp_be_stitch_input_buffer_config stitch_input_buffer; ++ struct pisp_be_tdn_output_buffer_config tdn_output_buffer; ++ struct pisp_be_stitch_output_buffer_config stitch_output_buffer; ++ struct pisp_be_output_buffer_config ++ output_buffer[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_hog_buffer_config hog_buffer; ++ /* Processing configuration: */ ++ struct pisp_be_global_config global; ++ struct pisp_image_format_config input_format; ++ struct pisp_decompress_config decompress; ++ struct pisp_be_dpc_config dpc; ++ struct pisp_be_geq_config geq; ++ struct pisp_image_format_config tdn_input_format; ++ struct pisp_decompress_config tdn_decompress; ++ struct pisp_be_tdn_config tdn; ++ struct pisp_compress_config tdn_compress; ++ struct pisp_image_format_config tdn_output_format; ++ struct pisp_be_sdn_config sdn; ++ struct pisp_bla_config blc; ++ struct pisp_compress_config stitch_compress; ++ struct pisp_image_format_config stitch_output_format; ++ struct pisp_image_format_config stitch_input_format; ++ struct pisp_decompress_config stitch_decompress; ++ struct pisp_be_stitch_config stitch; ++ struct pisp_be_lsc_config lsc; ++ struct pisp_wbg_config wbg; ++ struct pisp_be_cdn_config cdn; ++ struct pisp_be_cac_config cac; ++ struct pisp_be_debin_config debin; ++ struct pisp_be_tonemap_config tonemap; ++ struct pisp_be_demosaic_config demosaic; ++ struct pisp_be_ccm_config ccm; ++ struct pisp_be_sat_control_config sat_control; ++ struct pisp_be_ccm_config ycbcr; ++ struct pisp_be_sharpen_config sharpen; ++ struct pisp_be_false_colour_config false_colour; ++ struct pisp_be_sh_fc_combine_config sh_fc_combine; ++ struct pisp_be_ccm_config ycbcr_inverse; ++ struct pisp_be_gamma_config gamma; ++ struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_output_format_config ++ output_format[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_hog_config hog; ++ struct pisp_be_axi_config axi; ++ /* Non-register fields: */ ++ struct pisp_be_lsc_extra lsc_extra; ++ struct pisp_be_cac_extra cac_extra; ++ struct pisp_be_downscale_extra ++ downscale_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS]; ++ struct pisp_be_crop_config crop; ++ struct pisp_image_format_config hog_format; ++ __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ ++ __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ ++ __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ ++} __attribute__((packed)); ++ ++/** ++ * enum pisp_tile_edge - PiSP Back End Tile position ++ * @PISP_LEFT_EDGE: Left edge tile ++ * @PISP_RIGHT_EDGE: Right edge tile ++ * @PISP_TOP_EDGE: Top edge tile ++ * @PISP_BOTTOM_EDGE: Bottom edge tile ++ */ ++enum pisp_tile_edge { ++ PISP_LEFT_EDGE = (1 << 0), ++ PISP_RIGHT_EDGE = (1 << 1), ++ PISP_TOP_EDGE = (1 << 2), ++ PISP_BOTTOM_EDGE = (1 << 3) ++}; ++ ++/** ++ * struct pisp_tile - Raspberry Pi PiSP Back End tile configuration ++ * ++ * Tile parameters: each set of tile parameters is a 160-bytes block of data ++ * which contains the tile processing parameters. ++ * ++ * @edge: Edge tile flag ++ * @pad0: Padding bytes ++ * @input_addr_offset: Top-left pixel offset, in bytes ++ * @input_addr_offset2: Top-left pixel offset, in bytes for the second/ ++ * third image planes ++ * @input_offset_x: Horizontal offset in pixels of this tile in the ++ * input image ++ * @input_offset_y: Vertical offset in pixels of this tile in the ++ * input image ++ * @input_width: Width in pixels of this tile ++ * @input_height: Height in pixels of the this tile ++ * @tdn_input_addr_offset: TDN input image offset, in bytes ++ * @tdn_output_addr_offset: TDN output image offset, in bytes ++ * @stitch_input_addr_offset: Stitch input image offset, in bytes ++ * @stitch_output_addr_offset: Stitch output image offset, in bytes ++ * @lsc_grid_offset_x: Horizontal offset in the LSC table for this tile ++ * @lsc_grid_offset_y: Vertical offset in the LSC table for this tile ++ * @cac_grid_offset_x: Horizontal offset in the CAC table for this tile ++ * @cac_grid_offset_y: Horizontal offset in the CAC table for this tile ++ * @crop_x_start: Number of pixels cropped from the left of the ++ * tile ++ * @crop_x_end: Number of pixels cropped from the right of the ++ * tile ++ * @crop_y_start: Number of pixels cropped from the top of the ++ * tile ++ * @crop_y_end: Number of pixels cropped from the bottom of the ++ * tile ++ * @downscale_phase_x: Initial horizontal phase in pixels ++ * @downscale_phase_y: Initial vertical phase in pixels ++ * @resample_in_width: Width in pixels of the tile entering the ++ * Resample block ++ * @resample_in_height: Height in pixels of the tile entering the ++ * Resample block ++ * @resample_phase_x: Initial horizontal phase for the Resample block ++ * @resample_phase_y: Initial vertical phase for the Resample block ++ * @output_offset_x: Horizontal offset in pixels where the tile will ++ * be written into the output image ++ * @output_offset_y: Vertical offset in pixels where the tile will be ++ * written into the output image ++ * @output_width: Width in pixels in the output image of this tile ++ * @output_height: Height in pixels in the output image of this tile ++ * @output_addr_offset: Offset in bytes into the output buffer ++ * @output_addr_offset2: Offset in bytes into the output buffer for the ++ * second and third plane ++ * @output_hog_addr_offset: Offset in bytes into the HOG buffer where ++ * results of this tile are to be written ++ */ ++struct pisp_tile { ++ __u8 edge; /* enum pisp_tile_edge */ ++ __u8 pad0[3]; ++ /* 4 bytes */ ++ __u32 input_addr_offset; ++ __u32 input_addr_offset2; ++ __u16 input_offset_x; ++ __u16 input_offset_y; ++ __u16 input_width; ++ __u16 input_height; ++ /* 20 bytes */ ++ __u32 tdn_input_addr_offset; ++ __u32 tdn_output_addr_offset; ++ __u32 stitch_input_addr_offset; ++ __u32 stitch_output_addr_offset; ++ /* 36 bytes */ ++ __u32 lsc_grid_offset_x; ++ __u32 lsc_grid_offset_y; ++ /* 44 bytes */ ++ __u32 cac_grid_offset_x; ++ __u32 cac_grid_offset_y; ++ /* 52 bytes */ ++ __u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS]; ++ /* 68 bytes */ ++ /* Ordering is planes then branches */ ++ __u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ /* 92 bytes */ ++ __u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS]; ++ /* 100 bytes */ ++ /* Ordering is planes then branches */ ++ __u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS]; ++ /* 124 bytes */ ++ __u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 output_width[PISP_BACK_END_NUM_OUTPUTS]; ++ __u16 output_height[PISP_BACK_END_NUM_OUTPUTS]; ++ /* 140 bytes */ ++ __u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS]; ++ __u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS]; ++ /* 156 bytes */ ++ __u32 output_hog_addr_offset; ++ /* 160 bytes */ ++} __attribute__((packed)); ++ ++/** ++ * struct pisp_be_tiles_config - Raspberry Pi PiSP Back End configuration ++ * @tiles: Tile descriptors ++ * @num_tiles: Number of tiles ++ * @config: PiSP Back End configuration ++ */ ++struct pisp_be_tiles_config { ++ struct pisp_be_config config; ++ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES]; ++ __u32 num_tiles; ++} __attribute__((packed)); ++ ++#endif /* _UAPI_PISP_BE_CONFIG_H_ */ +diff --git a/include/uapi/linux/media/raspberrypi/pisp_common.h b/include/uapi/linux/media/raspberrypi/pisp_common.h +new file mode 100644 +index 000000000000..cbdccfed1261 +--- /dev/null ++++ b/include/uapi/linux/media/raspberrypi/pisp_common.h +@@ -0,0 +1,202 @@ ++/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ ++/* ++ * RP1 PiSP common definitions. ++ * ++ * Copyright (C) 2021 - Raspberry Pi Ltd. ++ * ++ */ ++#ifndef _UAPI_PISP_COMMON_H_ ++#define _UAPI_PISP_COMMON_H_ ++ ++#include ++ ++struct pisp_image_format_config { ++ /* size in pixels */ ++ __u16 width; ++ __u16 height; ++ /* must match struct pisp_image_format below */ ++ __u32 format; ++ __s32 stride; ++ /* some planar image formats will need a second stride */ ++ __s32 stride2; ++} __attribute__((packed)); ++ ++enum pisp_bayer_order { ++ /* ++ * Note how bayer_order&1 tells you if G is on the even pixels of the ++ * checkerboard or not, and bayer_order&2 tells you if R is on the even ++ * rows or is swapped with B. Note that if the top (of the 8) bits is ++ * set, this denotes a monochrome or greyscale image, and the lower bits ++ * should all be ignored. ++ */ ++ PISP_BAYER_ORDER_RGGB = 0, ++ PISP_BAYER_ORDER_GBRG = 1, ++ PISP_BAYER_ORDER_BGGR = 2, ++ PISP_BAYER_ORDER_GRBG = 3, ++ PISP_BAYER_ORDER_GREYSCALE = 128 ++}; ++ ++enum pisp_image_format { ++ /* ++ * Precise values are mostly tbd. Generally these will be portmanteau ++ * values comprising bit fields and flags. This format must be shared ++ * throughout the PiSP. ++ */ ++ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000, ++ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001, ++ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002, ++ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003, ++ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003, ++ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000, ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010, ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020, ++ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030, ++ ++ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000, ++ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100, ++ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200, ++ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300, ++ ++ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000, ++ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000, ++ ++ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000, ++ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000, ++ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000, ++ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000, ++ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000, ++ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000, ++ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000, ++ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000, ++ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000, ++ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000, ++ ++ PISP_IMAGE_FORMAT_BPP_32 = 0x00100000, ++ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000, ++ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000, ++ ++ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000, ++ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000, ++ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000, ++ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000, ++ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000, ++ ++ /* Lastly a few specific instantiations of the above. */ ++ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16, ++ PISP_IMAGE_FORMAT_THREE_16 = PISP_IMAGE_FORMAT_BPS_16 | ++ PISP_IMAGE_FORMAT_THREE_CHANNEL ++}; ++ ++#define PISP_IMAGE_FORMAT_BPS_8(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8) ++#define PISP_IMAGE_FORMAT_BPS_10(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10) ++#define PISP_IMAGE_FORMAT_BPS_12(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12) ++#define PISP_IMAGE_FORMAT_BPS_16(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16) ++#define PISP_IMAGE_FORMAT_BPS(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \ ++ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8) ++#define PISP_IMAGE_FORMAT_SHIFT(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1) ++#define PISP_IMAGE_FORMAT_THREE_CHANNEL(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL) ++#define PISP_IMAGE_FORMAT_SINGLE_CHANNEL(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)) ++#define PISP_IMAGE_FORMAT_COMPRESSED(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \ ++ PISP_IMAGE_FORMAT_UNCOMPRESSED) ++#define PISP_IMAGE_FORMAT_SAMPLING_444(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_444) ++#define PISP_IMAGE_FORMAT_SAMPLING_422(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_422) ++#define PISP_IMAGE_FORMAT_SAMPLING_420(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \ ++ PISP_IMAGE_FORMAT_SAMPLING_420) ++#define PISP_IMAGE_FORMAT_ORDER_NORMAL(fmt) \ ++ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)) ++#define PISP_IMAGE_FORMAT_ORDER_SWAPPED(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED) ++#define PISP_IMAGE_FORMAT_INTERLEAVED(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED) ++#define PISP_IMAGE_FORMAT_SEMIPLANAR(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR) ++#define PISP_IMAGE_FORMAT_PLANAR(fmt) \ ++ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \ ++ PISP_IMAGE_FORMAT_PLANARITY_PLANAR) ++#define PISP_IMAGE_FORMAT_WALLPAPER(fmt) \ ++ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL) ++#define PISP_IMAGE_FORMAT_BPP_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32) ++#define PISP_IMAGE_FORMAT_HOG(fmt) \ ++ ((fmt) & \ ++ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED)) ++ ++#define PISP_WALLPAPER_WIDTH 128 /* in bytes */ ++ ++struct pisp_bla_config { ++ __u16 black_level_r; ++ __u16 black_level_gr; ++ __u16 black_level_gb; ++ __u16 black_level_b; ++ __u16 output_black_level; ++ __u8 pad[2]; ++} __attribute__((packed)); ++ ++struct pisp_wbg_config { ++ __u16 gain_r; ++ __u16 gain_g; ++ __u16 gain_b; ++ __u8 pad[2]; ++} __attribute__((packed)); ++ ++struct pisp_compress_config { ++ /* value subtracted from incoming data */ ++ __u16 offset; ++ __u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ __u8 mode; ++} __attribute__((packed)); ++ ++struct pisp_decompress_config { ++ /* value added to reconstructed data */ ++ __u16 offset; ++ __u8 pad; ++ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */ ++ __u8 mode; ++} __attribute__((packed)); ++ ++enum pisp_axi_flags { ++ /* ++ * round down bursts to end at a 32-byte boundary, to align following ++ * bursts ++ */ ++ PISP_AXI_FLAG_ALIGN = 128, ++ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */ ++ PISP_AXI_FLAG_PAD = 64, ++ /* for FE writer: Use Output FIFO level to trigger "panic" */ ++ PISP_AXI_FLAG_PANIC = 32, ++}; ++ ++struct pisp_axi_config { ++ /* ++ * burst length minus one, which must be in the range 0:15; OR'd with ++ * flags ++ */ ++ __u8 maxlen_flags; ++ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */ ++ __u8 cache_prot; ++ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */ ++ __u16 qos; ++} __attribute__((packed)); ++ ++#endif /* _UAPI_PISP_COMMON_H_ */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h -index c3604a0a3e30..cfd6998a5b5a 100644 +index c3604a0a3e30..22bfc38787cc 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h -@@ -203,6 +203,10 @@ enum v4l2_colorfx { +@@ -203,6 +203,16 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0) +/* The base for the bcm2835-isp driver controls. + * We reserve 16 controls for this driver. */ +#define V4L2_CID_USER_BCM2835_ISP_BASE (V4L2_CID_USER_BASE + 0x10e0) ++ ++/* ++ * The base for IMX500 driver controls. ++ * We reserve 16 controls for this driver. ++ */ ++#define V4L2_CID_USER_IMX500_BASE (V4L2_CID_USER_BASE + 0x2000) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -@@ -1004,6 +1008,7 @@ enum v4l2_auto_n_preset_white_balance { +@@ -1004,6 +1014,7 @@ enum v4l2_auto_n_preset_white_balance { V4L2_WHITE_BALANCE_FLASH = 7, V4L2_WHITE_BALANCE_CLOUDY = 8, V4L2_WHITE_BALANCE_SHADE = 9, @@ -239729,7 +257577,7 @@ index c3604a0a3e30..cfd6998a5b5a 100644 #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index 78260e5d9985..d728b0a01d5f 100644 +index 78260e5d9985..f8157c9c9da6 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -82,6 +82,11 @@ @@ -239744,8 +257592,12 @@ index 78260e5d9985..d728b0a01d5f 100644 /* * E N U M S */ -@@ -584,6 +589,10 @@ struct v4l2_pix_format { +@@ -582,8 +587,14 @@ struct v4l2_pix_format { + + /* RGB formats (6 or 8 bytes per pixel) */ #define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */ ++#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 48 BGR 16-bit per component */ ++#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 48 RGB 16-bit per component */ #define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */ +/* RGB formats (6 bytes per pixel) */ @@ -239755,7 +257607,7 @@ index 78260e5d9985..d728b0a01d5f 100644 /* Grey formats */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ #define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ -@@ -598,6 +607,8 @@ struct v4l2_pix_format { +@@ -598,6 +609,8 @@ struct v4l2_pix_format { /* Grey bit-packed formats */ #define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ #define V4L2_PIX_FMT_Y10P v4l2_fourcc('Y', '1', '0', 'P') /* 10 Greyscale, MIPI RAW10 packed */ @@ -239764,7 +257616,7 @@ index 78260e5d9985..d728b0a01d5f 100644 #define V4L2_PIX_FMT_IPU3_Y10 v4l2_fourcc('i', 'p', '3', 'y') /* IPU3 packed 10-bit greyscale */ /* Palette formats */ -@@ -804,6 +815,10 @@ struct v4l2_pix_format { +@@ -804,6 +817,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */ #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ @@ -239775,7 +257627,7 @@ index 78260e5d9985..d728b0a01d5f 100644 /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ -@@ -811,6 +826,19 @@ struct v4l2_pix_format { +@@ -811,6 +828,19 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_IPU3_SGRBG10 v4l2_fourcc('i', 'p', '3', 'G') /* IPU3 packed 10-bit GRBG bayer */ #define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */ @@ -239795,7 +257647,7 @@ index 78260e5d9985..d728b0a01d5f 100644 /* SDR formats - used only for Software Defined Radio devices */ #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ #define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */ -@@ -833,11 +861,23 @@ struct v4l2_pix_format { +@@ -833,11 +863,23 @@ struct v4l2_pix_format { #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ #define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ @@ -239820,44 +257672,10 @@ index 78260e5d9985..d728b0a01d5f 100644 #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c -index dd8eed3c6e31..7b717aa93c47 100644 +index 555bcb07df6c..0089f89d85ba 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c -@@ -6170,6 +6170,9 @@ int __init cgroup_init_early(void) - return 0; - } - -+static u16 cgroup_enable_mask __initdata; -+static int __init cgroup_disable(char *str); -+ - /** - * cgroup_init - cgroup initialization - * -@@ -6203,6 +6206,12 @@ int __init cgroup_init(void) - - cgroup_unlock(); - -+ /* -+ * Apply an implicit disable, knowing that an explicit enable will -+ * prevent if from doing anything. -+ */ -+ cgroup_disable("memory"); -+ - for_each_subsys(ss, ssid) { - if (ss->early_init) { - struct cgroup_subsys_state *css = -@@ -6861,6 +6870,10 @@ static int __init cgroup_disable(char *str) - strcmp(token, ss->legacy_name)) - continue; - -+ /* An explicit cgroup_enable overrides a disable */ -+ if (cgroup_enable_mask & (1 << i)) -+ continue; -+ - static_branch_disable(cgroup_subsys_enabled_key[i]); - pr_info("Disabling %s control group subsystem\n", - ss->name); -@@ -6879,6 +6892,31 @@ static int __init cgroup_disable(char *str) +@@ -6879,6 +6879,31 @@ static int __init cgroup_disable(char *str) } __setup("cgroup_disable=", cgroup_disable); @@ -239876,7 +257694,7 @@ index dd8eed3c6e31..7b717aa93c47 100644 + strcmp(token, ss->legacy_name)) + continue; + -+ cgroup_enable_mask |= 1 << i; ++ cgroup_feature_disable_mask &= ~(1 << i); + static_branch_enable(cgroup_subsys_enabled_key[i]); + pr_info("Enabling %s control group subsystem\n", + ss->name); @@ -239890,7 +257708,7 @@ index dd8eed3c6e31..7b717aa93c47 100644 static int __init enable_cgroup_debug(char *str) diff --git a/kernel/resource.c b/kernel/resource.c -index e3f5680a564c..ded9cf87d603 100644 +index 635e858db0fe..4e0033e5ba28 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -200,6 +200,12 @@ static int __release_resource(struct resource *old, bool release_child) @@ -239906,11 +257724,158 @@ index e3f5680a564c..ded9cf87d603 100644 p = &old->parent->child; for (;;) { tmp = *p; +diff --git a/lib/earlycpio.c b/lib/earlycpio.c +index d2c37d64fd0c..4b1ce69a6ee5 100644 +--- a/lib/earlycpio.c ++++ b/lib/earlycpio.c +@@ -139,3 +139,4 @@ struct cpio_data find_cpio_data(const char *path, void *data, + quit: + return cd; + } ++EXPORT_SYMBOL_GPL(find_cpio_data); +diff --git a/mm/cma.c b/mm/cma.c +index 61c92b9b7664..5715b4f84bd7 100644 +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -623,3 +623,39 @@ int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data) + + return 0; + } ++ ++struct cma_check_range_data { ++ u64 start, end; ++}; ++ ++static int check_range(struct cma *cma_, void *data) ++{ ++ struct cma_check_range_data *range = data; ++ struct cma_check_range_data cma; ++ bool starts_in_range; ++ bool ends_in_range; ++ ++ cma.start = cma_get_base(cma_); ++ cma.end = cma.start + cma_get_size(cma_) - 1; ++ ++ starts_in_range = cma.start >= range->start && cma.start <= range->end; ++ ends_in_range = cma.end >= range->start && cma.end <= range->end; ++ ++ if (starts_in_range == ends_in_range) ++ return 0; ++ ++ pr_notice("CMA %s [%llx-%llx] straddles range [%llx-%llx]\n", ++ cma_->name, cma.start, cma.end, range->start, range->end); ++ ++ return -EINVAL; ++} ++ ++int cma_check_range(u64 *start, u64 *end) ++{ ++ struct cma_check_range_data range = { ++ .start = *start, ++ .end = *end, ++ }; ++ ++ return cma_for_each_area(check_range, &range); ++} +diff --git a/mm/mempolicy.c b/mm/mempolicy.c +index f4dfeb5f052f..3ebb1b343284 100644 +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -2977,7 +2977,9 @@ void __init numa_policy_init(void) + /* Reset policy of current process to default */ + void numa_default_policy(void) + { +- do_set_mempolicy(MPOL_DEFAULT, 0, NULL); ++ struct mempolicy *pol = &default_policy; ++ ++ do_set_mempolicy(pol->mode, pol->flags, &pol->nodes); + } + + /* +@@ -2996,7 +2998,6 @@ static const char * const policy_modes[] = + }; + + +-#ifdef CONFIG_TMPFS + /** + * mpol_parse_str - parse string to mempolicy, for tmpfs mpol mount option. + * @str: string containing mempolicy to parse +@@ -3009,13 +3010,18 @@ static const char * const policy_modes[] = + */ + int mpol_parse_str(char *str, struct mempolicy **mpol) + { +- struct mempolicy *new = NULL; ++ struct mempolicy *new; + unsigned short mode_flags; + nodemask_t nodes; + char *nodelist = strchr(str, ':'); + char *flags = strchr(str, '='); + int err = 1, mode; + ++ if (*mpol) ++ new = *mpol; ++ else ++ new = NULL; ++ + if (flags) + *flags++ = '\0'; /* terminate mode string */ + +@@ -3094,9 +3100,16 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) + goto out; + } + +- new = mpol_new(mode, mode_flags, &nodes); +- if (IS_ERR(new)) +- goto out; ++ if (!new) { ++ new = mpol_new(mode, mode_flags, &nodes); ++ if (IS_ERR(new)) ++ goto out; ++ } else { ++ atomic_set(&new->refcnt, 1); ++ new->mode = mode; ++ new->flags = mode_flags; ++ new->home_node = NUMA_NO_NODE; ++ } + + /* + * Save nodes for mpol_to_str() to show the tmpfs mount options +@@ -3129,7 +3142,29 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) + *mpol = new; + return err; + } +-#endif /* CONFIG_TMPFS */ ++ ++static int __init setup_numapolicy(char *str) ++{ ++ struct mempolicy pol = { }, *ppol = &pol; ++ char buf[128]; ++ int ret; ++ ++ if (str) ++ ret = mpol_parse_str(str, &ppol); ++ else ++ ret = -EINVAL; ++ ++ if (!ret) { ++ default_policy = pol; ++ mpol_to_str(buf, sizeof(buf), &pol); ++ pr_info("NUMA default policy overridden to '%s'\n", buf); ++ } else { ++ pr_warn("Unable to parse numa_policy=\n"); ++ } ++ ++ return ret == 0; ++} ++__setup("numa_policy=", setup_numapolicy); + + /** + * mpol_to_str - format a mempolicy structure for printing diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 4652dc453964..b9ab4d4b2353 100644 +index 00c9050a65ff..37ac685dd043 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -206,6 +206,27 @@ EXPORT_SYMBOL(node_states); +@@ -207,6 +207,27 @@ EXPORT_SYMBOL(node_states); gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; @@ -239938,7 +257903,7 @@ index 4652dc453964..b9ab4d4b2353 100644 /* * A cached value of the page's pageblock's migratetype, used when the page is * put on a pcplist. Used to avoid the pageblock migratetype lookup when -@@ -2123,12 +2144,13 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype, +@@ -2107,12 +2128,13 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype, if (IS_ENABLED(CONFIG_CMA)) { /* * Balance movable allocations between regular and CMA areas by @@ -239955,19 +257920,33 @@ index 4652dc453964..b9ab4d4b2353 100644 page = __rmqueue_cma_fallback(zone, order); if (page) return page; +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 96fc157666fc..bf99f71fc7f7 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4766,7 +4766,7 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + if (!folio) + continue; + +- if (!ptep_test_and_clear_young(vma, addr, pte + i)) ++ if (!ptep_clear_flush_young(vma, addr, pte + i)) + VM_WARN_ON_ONCE(true); + + young++; diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c -index 1bc58b324b73..e2ae1bd4dfd0 100644 +index c553b637cda7..1500bf5fdb4f 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c -@@ -4737,6 +4737,7 @@ static const struct { +@@ -4865,6 +4865,8 @@ static const struct { */ static int hci_dev_setup_sync(struct hci_dev *hdev) { -+ struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent); ++ struct fwnode_handle *fwnode = ++ hdev->dev.parent ? dev_fwnode(hdev->dev.parent) : NULL; int ret = 0; bool invalid_bdaddr; size_t i; -@@ -4765,7 +4766,8 @@ static int hci_dev_setup_sync(struct hci_dev *hdev) +@@ -4893,7 +4895,8 @@ static int hci_dev_setup_sync(struct hci_dev *hdev) test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); if (!ret) { if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) && @@ -239978,7 +257957,7 @@ index 1bc58b324b73..e2ae1bd4dfd0 100644 if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) && diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c -index 37f95ea8c7db..a40808483730 100644 +index 56f7f041c9a6..7a306dede89f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -885,16 +885,9 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, @@ -240000,16 +257979,16 @@ index 37f95ea8c7db..a40808483730 100644 return 0; } -@@ -2221,7 +2214,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) +@@ -2215,7 +2208,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (err) return SMP_UNSPECIFIED; - if (smp->method == REQ_OOB) { + if (smp->method == JUST_WORKS || smp->method == REQ_OOB) { - if (hcon->out) { + if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) { sc_dhkey_check(smp); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); -@@ -2236,9 +2229,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) +@@ -2230,9 +2223,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) confirm_hint = 0; confirm: @@ -241452,7 +259431,7 @@ index 000000000000..c5ab03f8c500 +0x9f, +0x21, diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst -index 4405d5b67578..9d8f14e3c732 100644 +index fa3ad33a19df..38af1db2a98e 100644 --- a/scripts/Makefile.dtbinst +++ b/scripts/Makefile.dtbinst @@ -18,9 +18,10 @@ include $(srctree)/scripts/Kbuild.include @@ -241476,10 +259455,10 @@ index 4405d5b67578..9d8f14e3c732 100644 .PHONY: $(PHONY) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib -index 68d0134bdbf9..116cfae5fa07 100644 +index 9443c7ca1183..0ad40aa42efe 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -346,6 +346,7 @@ DTC_FLAGS += -Wno-interrupt_provider \ +@@ -356,6 +356,7 @@ DTC_FLAGS += -Wno-interrupt_provider \ # Disable noisy checks by default ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wno-unit_address_vs_reg \ @@ -241487,7 +259466,7 @@ index 68d0134bdbf9..116cfae5fa07 100644 -Wno-avoid_unnecessary_addr_size \ -Wno-alias_paths \ -Wno-graph_child_address \ -@@ -421,6 +422,24 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE +@@ -435,6 +436,24 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE $(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE $(call if_changed_dep,dtc) @@ -241513,10 +259492,10 @@ index 68d0134bdbf9..116cfae5fa07 100644 # Bzip2 diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 4218057b0874..d27ba79e1208 100644 +index 4218057b0874..fa50cab51478 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig -@@ -26,3 +26,272 @@ config SND_BCM63XX_I2S_WHISTLER +@@ -26,3 +26,287 @@ config SND_BCM63XX_I2S_WHISTLER DSL/PON chips (bcm63158, bcm63178) If you don't know what to do here, say N @@ -241533,6 +259512,21 @@ index 4218057b0874..d27ba79e1208 100644 + help + Say Y or M if you want to add support for voiceHAT soundcard. + ++config SND_BCM2708_SOC_HIFIBERRY_ADC ++ tristate "Support for HifiBerry ADC" ++ select SND_SOC_PCM186X_I2C ++ select SND_RPI_HIFIBERRY_ADC ++ help ++ Say Y or M if you want to add support for HifiBerry ADC. ++ Use this module for HiFiBerry's ADC-only sound cards ++ ++config SND_BCM2708_SOC_HIFIBERRY_ADC8X ++ tristate "Support for HifiBerry ADC8X" ++ select SND_RPI_SIMPLE_SOUNDCARD ++ help ++ Say Y or M if you want to add support for HifiBerry ADC8X. ++ Note: ADC8X only works on PI5 ++ +config SND_BCM2708_SOC_HIFIBERRY_DAC + tristate "Support for HifiBerry DAC and DAC8X" + select SND_SOC_PCM5102A @@ -241790,10 +259784,10 @@ index 4218057b0874..d27ba79e1208 100644 + help + Say Y or M if you want to add support for tlv320aic3x add-on diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 7c2d7899603b..46d1ece070a3 100644 +index 7c2d7899603b..693161c6afdb 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile -@@ -12,4 +12,73 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o +@@ -12,4 +12,75 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o # BCM63XX Platform Support snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o @@ -241805,6 +259799,7 @@ index 7c2d7899603b..46d1ece070a3 100644 +snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o + +# BCM2708 Machine Support ++snd-soc-hifiberry-adc-objs := hifiberry_adc.o +snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o +snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o +snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o @@ -241838,6 +259833,7 @@ index 7c2d7899603b..46d1ece070a3 100644 +snd-soc-dacberry400-objs := dacberry400.o + +obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC) += snd-soc-hifiberry-adc.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o @@ -246066,7 +264062,7 @@ index 000000000000..870d24bf67a3 +MODULE_ALIAS("platform:audiosense-pi"); + diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index 9bda6499e66e..2d0fe53245f0 100644 +index 9bda6499e66e..952f6e5c7536 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -30,7 +30,6 @@ @@ -246077,7 +264073,29 @@ index 9bda6499e66e..2d0fe53245f0 100644 #include #include -@@ -830,8 +829,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) +@@ -620,6 +619,10 @@ static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream, + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + uint32_t cs_reg; + ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 256, ++ ~0); ++ + /* + * Clear both FIFOs if the one that should be started + * is not empty at the moment. This should only happen +@@ -701,6 +704,10 @@ static int bcm2835_i2s_startup(struct snd_pcm_substream *substream, + /* Should this still be running stop it */ + bcm2835_i2s_stop_clock(dev); + ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ 256, ~0); ++ + /* Enable PCM block */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_EN, BCM2835_I2S_EN); +@@ -830,8 +837,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) struct bcm2835_i2s_dev *dev; int ret; void __iomem *base; @@ -246087,7 +264105,7 @@ index 9bda6499e66e..2d0fe53245f0 100644 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); -@@ -846,7 +844,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) +@@ -846,7 +852,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) "could not get clk\n"); /* Request ioarea */ @@ -246096,7 +264114,7 @@ index 9bda6499e66e..2d0fe53245f0 100644 if (IS_ERR(base)) return PTR_ERR(base); -@@ -855,19 +853,11 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) +@@ -855,19 +861,11 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->i2s_regmap)) return PTR_ERR(dev->i2s_regmap); @@ -247504,10 +265522,10 @@ index 000000000000..ded4ba1a2815 +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/googlevoicehat-codec.c b/sound/soc/bcm/googlevoicehat-codec.c new file mode 100644 -index 000000000000..a2015896966c +index 000000000000..7ddda4173cb3 --- /dev/null +++ b/sound/soc/bcm/googlevoicehat-codec.c -@@ -0,0 +1,214 @@ +@@ -0,0 +1,213 @@ +/* + * Driver for the Google voiceHAT audio codec for Raspberry Pi. + * @@ -247605,8 +265623,7 @@ index 000000000000..a2015896966c + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; -+ struct voicehat_priv *voicehat = -+ snd_soc_component_get_drvdata(component); ++ struct voicehat_priv *voicehat = snd_soc_component_get_drvdata(component); + + if (voicehat->sdmode_delay_jiffies == 0) + return 0; @@ -247619,7 +265636,7 @@ index 000000000000..a2015896966c + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ if (dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dev_info(dai->dev, "Enabling audio amp...\n"); + queue_delayed_work( + system_power_efficient_wq, @@ -247630,7 +265647,7 @@ index 000000000000..a2015896966c + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ if (dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + cancel_delayed_work(&voicehat->enable_sdmode_work); + dev_info(dai->dev, "Disabling audio amp...\n"); + gpiod_set_value(voicehat->sdmode_gpio, 0); @@ -247722,6 +265739,320 @@ index 000000000000..a2015896966c +MODULE_DESCRIPTION("Google voiceHAT Codec driver"); +MODULE_AUTHOR("Peter Malkin "); +MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/bcm/hifiberry_adc.c b/sound/soc/bcm/hifiberry_adc.c +new file mode 100644 +index 000000000000..b543580ae63d +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_adc.c +@@ -0,0 +1,174 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * ASoC Driver for HiFiBerry ADC ++ * ++ * Author: Joerg Schambacher ++ * Copyright 2024 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/pcm186x.h" ++#include "hifiberry_adc_controls.h" ++ ++static bool leds_off; ++ ++static int pcm1863_add_controls(struct snd_soc_component *component) ++{ ++ snd_soc_add_component_controls(component, ++ pcm1863_snd_controls_card, ++ ARRAY_SIZE(pcm1863_snd_controls_card)); ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_adc_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ struct snd_soc_component *adc = codec_dai->component; ++ int ret; ++ ++ ret = pcm1863_add_controls(adc); ++ if (ret < 0) ++ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n", ++ ret); ++ ++ codec_dai->driver->capture.rates = ++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000; ++ ++ /* set GPIO2 to output, GPIO3 input */ ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); ++ if (leds_off) ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); ++ else ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_adc_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int channels = params_channels(params); ++ int width = snd_pcm_format_width(params_format(params)); ++ ++ /* Using powers of 2 allows for an integer clock divisor */ ++ width = width <= 16 ? 16 : 32; ++ ++ ret = snd_soc_dai_set_bclk_ratio(asoc_rtd_to_cpu(rtd, 0), channels * width); ++ return ret; ++} ++ ++/* machine stream operations */ ++static const struct snd_soc_ops snd_rpi_hifiberry_adc_ops = { ++ .hw_params = snd_rpi_hifiberry_adc_hw_params, ++}; ++ ++SND_SOC_DAILINK_DEFS(hifi, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_adc_dai[] = { ++{ ++ .name = "HiFiBerry ADC", ++ .stream_name = "HiFiBerry ADC HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_adc_ops, ++ .init = snd_rpi_hifiberry_adc_init, ++ SND_SOC_DAILINK_REG(hifi), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_adc = { ++ .name = "snd_rpi_hifiberry_adc", ++ .driver_name = "HifiberryAdc", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_hifiberry_adc_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_adc_dai), ++}; ++ ++static int snd_rpi_hifiberry_adc_probe(struct platform_device *pdev) ++{ ++ int ret = 0, i = 0; ++ struct snd_soc_card *card = &snd_rpi_hifiberry_adc; ++ ++ snd_rpi_hifiberry_adc.dev = &pdev->dev; ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_hifiberry_adc_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ for (i = 0; i < card->num_links; i++) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } ++ } ++ } ++ leds_off = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-adc,leds_off"); ++ ret = snd_soc_register_card(&snd_rpi_hifiberry_adc); ++ if (ret && ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static const struct of_device_id snd_rpi_hifiberry_adc_of_match[] = { ++ { .compatible = "hifiberry,hifiberry-adc", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_adc_of_match); ++ ++static struct platform_driver snd_rpi_hifiberry_adc_driver = { ++ .driver = { ++ .name = "snd-rpi-hifiberry-adc", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_hifiberry_adc_of_match, ++ }, ++ .probe = snd_rpi_hifiberry_adc_probe, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_adc_driver); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry ADC"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/bcm/hifiberry_adc_controls.h b/sound/soc/bcm/hifiberry_adc_controls.h +new file mode 100644 +index 000000000000..8d8911bb0afb +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_adc_controls.h +@@ -0,0 +1,128 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * ALSA mixer/Kcontrol definitions common to HiFiBerry ADCs ++ * ++ * used by DAC+ADC Pro (hifiberry_dacplusadcpro.c), ++ * ADC (hifiberry_adc.c) ++ * ++ * Author: Joerg Schambacher ++ * Copyright 2024 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++static const unsigned int pcm186x_adc_input_channel_sel_value[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x10 ++}; ++ ++static const char * const pcm186x_adcl_input_channel_sel_text[] = { ++ "No Select", ++ "VINL1[SE]", /* Default for ADCL */ ++ "VINL2[SE]", ++ "VINL2[SE] + VINL1[SE]", ++ "{VIN1P, VIN1M}[DIFF]" ++}; ++ ++static const char * const pcm186x_adcr_input_channel_sel_text[] = { ++ "No Select", ++ "VINR1[SE]", /* Default for ADCR */ ++ "VINR2[SE]", ++ "VINR2[SE] + VINR1[SE]", ++ "{VIN2P, VIN2M}[DIFF]" ++}; ++ ++static const struct soc_enum pcm186x_adc_input_channel_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), ++ pcm186x_adcl_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), ++ pcm186x_adcr_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++}; ++ ++static const unsigned int pcm186x_mic_bias_sel_value[] = { ++ 0x00, 0x01, 0x11 ++}; ++ ++static const char * const pcm186x_mic_bias_sel_text[] = { ++ "Mic Bias off", ++ "Mic Bias on", ++ "Mic Bias with Bypass Resistor" ++}; ++ ++static const struct soc_enum pcm186x_mic_bias_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, ++ GENMASK(4, 0), ++ ARRAY_SIZE(pcm186x_mic_bias_sel_text), ++ pcm186x_mic_bias_sel_text, ++ pcm186x_mic_bias_sel_value), ++}; ++ ++static const unsigned int pcm186x_gain_sel_value[] = { ++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, ++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ++ 0x50 ++}; ++ ++static const char * const pcm186x_gain_sel_text[] = { ++ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", ++ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", ++ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", ++ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", ++ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", ++ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", ++ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", ++ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", ++ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", ++ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", ++ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", ++ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", ++ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", ++ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", ++ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", ++ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", ++ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", ++ "39.0dB", "39.5dB", "40.0dB"}; ++ ++static const struct soc_enum pcm186x_gain_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++}; ++ ++static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { ++ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), ++ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), ++ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), ++ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), ++ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), ++}; diff --git a/sound/soc/bcm/hifiberry_dacplus.c b/sound/soc/bcm/hifiberry_dacplus.c new file mode 100644 index 000000000000..e400b1159836 @@ -248698,10 +267029,10 @@ index 000000000000..9d2711485e0e +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/bcm/hifiberry_dacplusadcpro.c b/sound/soc/bcm/hifiberry_dacplusadcpro.c new file mode 100644 -index 000000000000..70e59c0cd797 +index 000000000000..dd6a24e377eb --- /dev/null +++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -0,0 +1,606 @@ +@@ -0,0 +1,498 @@ +/* + * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control) + * @@ -248741,6 +267072,7 @@ index 000000000000..70e59c0cd797 + +#include "../codecs/pcm512x.h" +#include "../codecs/pcm186x.h" ++#include "hifiberry_adc_controls.h" + +#define HIFIBERRY_DACPRO_NOCLOCK 0 +#define HIFIBERRY_DACPRO_CLK44EN 1 @@ -248761,115 +267093,6 @@ index 000000000000..70e59c0cd797 +static bool digital_gain_0db_limit = true; +static bool leds_off; + -+static const unsigned int pcm186x_adc_input_channel_sel_value[] = { -+ 0x00, 0x01, 0x02, 0x03, 0x10 -+}; -+ -+static const char * const pcm186x_adcl_input_channel_sel_text[] = { -+ "No Select", -+ "VINL1[SE]", /* Default for ADCL */ -+ "VINL2[SE]", -+ "VINL2[SE] + VINL1[SE]", -+ "{VIN1P, VIN1M}[DIFF]" -+}; -+ -+static const char * const pcm186x_adcr_input_channel_sel_text[] = { -+ "No Select", -+ "VINR1[SE]", /* Default for ADCR */ -+ "VINR2[SE]", -+ "VINR2[SE] + VINR1[SE]", -+ "{VIN2P, VIN2M}[DIFF]" -+}; -+ -+static const struct soc_enum pcm186x_adc_input_channel_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, -+ PCM186X_ADC_INPUT_SEL_MASK, -+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), -+ pcm186x_adcl_input_channel_sel_text, -+ pcm186x_adc_input_channel_sel_value), -+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, -+ PCM186X_ADC_INPUT_SEL_MASK, -+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), -+ pcm186x_adcr_input_channel_sel_text, -+ pcm186x_adc_input_channel_sel_value), -+}; -+ -+static const unsigned int pcm186x_mic_bias_sel_value[] = { -+ 0x00, 0x01, 0x11 -+}; -+ -+static const char * const pcm186x_mic_bias_sel_text[] = { -+ "Mic Bias off", -+ "Mic Bias on", -+ "Mic Bias with Bypass Resistor" -+}; -+ -+static const struct soc_enum pcm186x_mic_bias_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, -+ GENMASK(4, 0), -+ ARRAY_SIZE(pcm186x_mic_bias_sel_text), -+ pcm186x_mic_bias_sel_text, -+ pcm186x_mic_bias_sel_value), -+}; -+ -+static const unsigned int pcm186x_gain_sel_value[] = { -+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, -+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, -+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, -+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, -+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, -+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, -+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, -+ 0x50 -+}; -+ -+static const char * const pcm186x_gain_sel_text[] = { -+ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", -+ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", -+ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", -+ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", -+ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", -+ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", -+ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", -+ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", -+ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", -+ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", -+ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", -+ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", -+ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", -+ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", -+ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", -+ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", -+ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", -+ "39.0dB", "39.5dB", "40.0dB"}; -+ -+static const struct soc_enum pcm186x_gain_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, -+ 0xff, -+ ARRAY_SIZE(pcm186x_gain_sel_text), -+ pcm186x_gain_sel_text, -+ pcm186x_gain_sel_value), -+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, -+ 0xff, -+ ARRAY_SIZE(pcm186x_gain_sel_text), -+ pcm186x_gain_sel_text, -+ pcm186x_gain_sel_value), -+}; -+ -+static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { -+ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), -+ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), -+ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), -+ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), -+ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), -+}; -+ +static int pcm1863_add_controls(struct snd_soc_component *component) +{ + snd_soc_add_component_controls(component, @@ -249816,10 +268039,10 @@ index 000000000000..502b9847be19 +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/iqaudio-codec.c b/sound/soc/bcm/iqaudio-codec.c new file mode 100644 -index 000000000000..1486318a7c91 +index 000000000000..08b9c51759cc --- /dev/null +++ b/sound/soc/bcm/iqaudio-codec.c -@@ -0,0 +1,278 @@ +@@ -0,0 +1,284 @@ +/* + * ASoC Driver for IQaudIO Raspberry Pi Codec board + * @@ -249949,13 +268172,19 @@ index 000000000000..1486318a7c91 + snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack"); + snd_soc_dapm_sync(&rtd->card->dapm); + -+ /* Set bclk ratio to align with codec's BCLK rate */ ++ /* Impose BCLK ratios otherwise the codec may cheat */ + ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64); + if (ret) { + dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n"); + return ret; + } + ++ ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); ++ if (ret) { ++ dev_err(rtd->dev, "Failed to set codec BCLK ratio\n"); ++ return ret; ++ } ++ + /* Set MCLK frequency to codec, onboard 11.2896MHz clock */ + return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600, + SND_SOC_CLOCK_OUT); @@ -253491,10 +271720,10 @@ index 000000000000..9a5cf91719fb +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/rpi-simple-soundcard.c b/sound/soc/bcm/rpi-simple-soundcard.c new file mode 100644 -index 000000000000..cc0f123570cd +index 000000000000..c8f681cb07ca --- /dev/null +++ b/sound/soc/bcm/rpi-simple-soundcard.c -@@ -0,0 +1,523 @@ +@@ -0,0 +1,560 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard. @@ -253751,6 +271980,41 @@ index 000000000000..cc0f123570cd + .dai = snd_hifiberrydacplusdsp_soundcard_dai, +}; + ++SND_SOC_DAILINK_DEFS(hifiberry_adc, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static int hifiberry_adc8x_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ ++ /* set limits of 8 channels and 192ksps sample rate ++ */ ++ codec_dai->driver->capture.channels_max = 8; ++ codec_dai->driver->capture.rates = SNDRV_PCM_RATE_8000_192000; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_link snd_hifiberry_adc8x_dai[] = { ++ { ++ .name = "HifiBerry ADC8x", ++ .stream_name = "HifiBerry ADC8x HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .init = hifiberry_adc8x_init, ++ SND_SOC_DAILINK_REG(hifiberry_adc), ++ }, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_hifiberry_adc8x = { ++ .card_name = "snd_rpi_hifiberry_adc8x", ++ .dai = snd_hifiberry_adc8x_dai, ++ .fixed_bclk_ratio = 64, ++}; ++ +SND_SOC_DAILINK_DEFS(hifiberry_amp, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")), @@ -253942,6 +272206,8 @@ index 000000000000..cc0f123570cd + .data = (void *) &drvdata_googlevoicehat }, + { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard", + .data = (void *) &drvdata_hifiberrydacplusdsp }, ++ { .compatible = "hifiberry,hifiberry-adc8x", ++ .data = (void *) &drvdata_hifiberry_adc8x }, + { .compatible = "hifiberry,hifiberry-amp", + .data = (void *) &drvdata_hifiberry_amp }, + { .compatible = "hifiberry,hifiberry-amp3", @@ -254805,6 +273071,71 @@ index 9c44b6283b8f..8e3b88d7d3af 100644 int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata) { struct cs42xx8_priv *cs42xx8; +diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c +index 3a6449c44b23..36439fbe0d76 100644 +--- a/sound/soc/codecs/da7213.c ++++ b/sound/soc/codecs/da7213.c +@@ -1181,6 +1181,8 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, + switch (params_width(params)) { + case 16: + dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE; ++ if (da7213->bclk_ratio == 64) ++ break; + dai_clk_mode = DA7213_DAI_BCLKS_PER_WCLK_32; /* 32bit for 1ch and 2ch */ + break; + case 20: +@@ -1196,6 +1198,9 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, + return -EINVAL; + } + ++ if (da7213->bclk_ratio == 32 && params_width(params) != 16) ++ return -EINVAL; ++ + /* Set sampling rate */ + switch (params_rate(params)) { + case 8000: +@@ -1358,6 +1363,21 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) + return 0; + } + ++static int da7213_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); ++ ++ if (ratio != 32 && ratio != 64) { ++ dev_err(component->dev, "Invalid bclk ratio %d\n", ratio); ++ return -EINVAL; ++ } ++ ++ da7213->bclk_ratio = ratio; ++ ++ return 0; ++} ++ + static int da7213_mute(struct snd_soc_dai *dai, int mute, int direction) + { + struct snd_soc_component *component = dai->component; +@@ -1554,6 +1574,7 @@ static int da7213_set_component_pll(struct snd_soc_component *component, + static const struct snd_soc_dai_ops da7213_dai_ops = { + .hw_params = da7213_hw_params, + .set_fmt = da7213_set_dai_fmt, ++ .set_bclk_ratio = da7213_set_bclk_ratio, + .mute_stream = da7213_mute, + .no_capture_mute = 1, + }; +diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h +index 4ca9cfdea06d..cb7d579c4aad 100644 +--- a/sound/soc/codecs/da7213.h ++++ b/sound/soc/codecs/da7213.h +@@ -538,6 +538,7 @@ struct da7213_priv { + struct clk *mclk; + unsigned int mclk_rate; + unsigned int out_rate; ++ unsigned int bclk_ratio; + int clk_src; + bool master; + bool alc_calib_auto; diff --git a/sound/soc/codecs/i-sabre-codec.c b/sound/soc/codecs/i-sabre-codec.c new file mode 100644 index 000000000000..518c57f4558e @@ -257385,7 +275716,7 @@ index 000000000000..8f019e048987 + +#endif /* _TAS5713_H */ diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c -index 9ea4be56d3b7..e45c31741cc6 100644 +index 9ea4be56d3b7..7e3a1ae1f84c 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -21,7 +21,7 @@ @@ -257414,7 +275745,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 if (dev->use_pio || dev->is_jh7110) i2s_disable_irqs(dev, substream->stream, 8); -@@ -225,33 +220,32 @@ static void i2s_stop(struct dw_i2s_dev *dev, +@@ -225,41 +220,43 @@ static void i2s_stop(struct dw_i2s_dev *dev, if (!dev->active) { i2s_write_reg(dev->i2s_base, CER, 0); @@ -257447,6 +275778,8 @@ index 9ea4be56d3b7..e45c31741cc6 100644 struct i2s_clk_config_data *config = &dev->config; - + u32 dmacr; ++ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); ++ u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); i2s_disable_channels(dev, stream); @@ -257460,15 +275793,17 @@ index 9ea4be56d3b7..e45c31741cc6 100644 for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { i2s_write_reg(dev->i2s_base, TCR(ch_reg), -@@ -260,6 +254,7 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) - dev->fifo_th - 1); + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), +- dev->fifo_th - 1); ++ fifo_depth - dev->fifo_th - 1); i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN | dev->tdm_mask << TER_TXSLOT_SHIFT); + dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg); } else { i2s_write_reg(dev->i2s_base, RCR(ch_reg), dev->xfer_resolution); -@@ -267,9 +262,11 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) +@@ -267,9 +264,11 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) dev->fifo_th - 1); i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN | dev->tdm_mask << RER_RXSLOT_SHIFT); @@ -257481,7 +275816,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 } static int dw_i2s_hw_params(struct snd_pcm_substream *substream, -@@ -277,24 +274,32 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +@@ -277,24 +276,32 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); struct i2s_clk_config_data *config = &dev->config; @@ -257517,7 +275852,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 dev->xfer_resolution = 0x05; break; -@@ -315,17 +320,37 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +@@ -315,17 +322,37 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, case TWO_CHANNEL_SUPPORT: break; default: @@ -257558,7 +275893,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 if (dev->i2s_clk_cfg) { ret = dev->i2s_clk_cfg(config); if (ret < 0) { -@@ -333,8 +358,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +@@ -333,8 +360,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return ret; } } else { @@ -257568,16 +275903,16 @@ index 9ea4be56d3b7..e45c31741cc6 100644 ret = clk_set_rate(dev->clk, bitclk); if (ret) { -@@ -343,10 +367,71 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, +@@ -343,10 +369,71 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return ret; } } + + i2s_write_reg(dev->i2s_base, CCR, dev->ccr); - } - return 0; - } - ++ } ++ return 0; ++} ++ +static int dw_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ @@ -257602,7 +275937,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + dma_data = &dev->capture_dma_data; + dmacr |= DMACR_DMAEN_RX; -+ } + } + + snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); + i2s_write_reg(dev->i2s_base, I2S_DMACR, dmacr); @@ -257614,9 +275949,9 @@ index 9ea4be56d3b7..e45c31741cc6 100644 + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; + } + -+ return 0; -+} -+ + return 0; + } + +static void dw_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ @@ -257640,7 +275975,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 static int dw_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { -@@ -374,9 +459,12 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream, +@@ -374,9 +461,12 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream, i2s_start(dev, substream); break; @@ -257654,7 +275989,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 dev->active--; i2s_stop(dev, substream); break; -@@ -460,6 +548,18 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask +@@ -460,6 +550,18 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask return 0; } @@ -257673,7 +276008,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 static int dw_i2s_dai_probe(struct snd_soc_dai *dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -@@ -471,11 +571,13 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai) +@@ -471,11 +573,13 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops dw_i2s_dai_ops = { .probe = dw_i2s_dai_probe, .startup = dw_i2s_startup, @@ -257687,7 +276022,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 }; #ifdef CONFIG_PM -@@ -606,7 +708,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, +@@ -606,7 +710,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, idx = 1; dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->playback.channels_max = @@ -257696,7 +276031,7 @@ index 9ea4be56d3b7..e45c31741cc6 100644 dw_i2s_dai->playback.formats = formats[idx]; dw_i2s_dai->playback.rates = rates; } -@@ -620,7 +722,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, +@@ -620,7 +724,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, idx = 1; dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; dw_i2s_dai->capture.channels_max = @@ -257705,7 +276040,18 @@ index 9ea4be56d3b7..e45c31741cc6 100644 dw_i2s_dai->capture.formats = formats[idx]; dw_i2s_dai->capture.rates = rates; } -@@ -702,7 +804,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, +@@ -681,8 +785,8 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, + dev->capture_dma_data.pd.data = pdata->capture_dma_data; + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; +- dev->play_dma_data.pd.max_burst = 16; +- dev->capture_dma_data.pd.max_burst = 16; ++ dev->play_dma_data.pd.max_burst = dev->fifo_th; ++ dev->capture_dma_data.pd.max_burst = dev->fifo_th; + dev->play_dma_data.pd.addr_width = bus_widths[idx]; + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; + dev->play_dma_data.pd.filter = pdata->filter; +@@ -702,7 +806,7 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, u32 idx2; int ret; @@ -257714,16 +276060,45 @@ index 9ea4be56d3b7..e45c31741cc6 100644 if (ret < 0) return ret; -@@ -968,6 +1070,7 @@ static int dw_i2s_probe(struct platform_device *pdev) +@@ -713,7 +817,10 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; + dev->play_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2]) >> 8; +- dev->play_dma_data.dt.maxburst = 16; ++ if (dev->max_dma_burst) ++ dev->play_dma_data.dt.maxburst = dev->max_dma_burst; ++ else ++ dev->play_dma_data.dt.maxburst = fifo_depth / 2; + } + if (COMP1_RX_ENABLED(comp1)) { + idx2 = COMP2_RX_WORDSIZE_0(comp2); +@@ -722,9 +829,14 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; + dev->capture_dma_data.dt.fifo_size = fifo_depth * + (fifo_width[idx2] >> 8); +- dev->capture_dma_data.dt.maxburst = 16; ++ if (dev->max_dma_burst) ++ dev->capture_dma_data.dt.maxburst = dev->max_dma_burst; ++ else ++ dev->capture_dma_data.dt.maxburst = fifo_depth / 2; + } + ++ if (dev->max_dma_burst) ++ dev->fifo_th = min(dev->max_dma_burst, dev->fifo_th); + return 0; + + } +@@ -968,6 +1080,8 @@ static int dw_i2s_probe(struct platform_device *pdev) } } ++ of_property_read_u32(pdev->dev.of_node, "dma-maxburst", &dev->max_dma_burst); + dev->bclk_ratio = 0; dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; if (pdata) { diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h -index dce88c9ad5f3..9f21eb68bd6c 100644 +index dce88c9ad5f3..afff89db5dbb 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -63,6 +63,17 @@ @@ -257744,7 +276119,7 @@ index dce88c9ad5f3..9f21eb68bd6c 100644 /* I2SCOMPRegisters */ #define I2S_COMP_PARAM_2 0x01F0 #define I2S_COMP_PARAM_1 0x01F4 -@@ -117,6 +128,7 @@ struct dw_i2s_dev { +@@ -117,10 +128,12 @@ struct dw_i2s_dev { unsigned int quirks; unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp2; @@ -257752,6 +276127,11 @@ index dce88c9ad5f3..9f21eb68bd6c 100644 struct device *dev; u32 ccr; u32 xfer_resolution; + u32 fifo_th; ++ u32 max_dma_burst; + u32 l_reg; + u32 r_reg; + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e65fe3a7c3e4..df3a3046c9f8 100644 --- a/sound/soc/soc-core.c @@ -257792,10 +276172,10 @@ index e65fe3a7c3e4..df3a3046c9f8 100644 return ret; } diff --git a/sound/usb/card.c b/sound/usb/card.c -index 1b2edc0fd2e9..297d6ad1d8c0 100644 +index 7743ea983b1a..cee90e193d22 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c -@@ -857,8 +857,14 @@ static int usb_audio_probe(struct usb_interface *intf, +@@ -863,8 +863,14 @@ static int usb_audio_probe(struct usb_interface *intf, if (ignore_ctl_error) chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR; @@ -257812,10 +276192,10 @@ index 1b2edc0fd2e9..297d6ad1d8c0 100644 /* * For devices with more than one control interface, we assume the diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c -index 09712e61c606..48e0226b2d34 100644 +index 37211ad31ec8..744a316f47bc 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c -@@ -2185,6 +2185,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { +@@ -2197,6 +2197,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */ QUIRK_FLAG_ALIGN_TRANSFER), diff --git a/raspberrypi-kernel.spec b/raspberrypi-kernel.spec index 33e0a5e..14c1149 100644 --- a/raspberrypi-kernel.spec +++ b/raspberrypi-kernel.spec @@ -2,13 +2,13 @@ %global KernelVer %{version}-%{release}.raspi.%{_target_cpu} -%global hulkrelease 28.0.0 +%global hulkrelease 64.0.0 %global debug_package %{nil} Name: raspberrypi-kernel Version: 6.6.0 -Release: %{hulkrelease}.5 +Release: %{hulkrelease}.6 Summary: Linux Kernel License: GPLv2 URL: http://www.kernel.org/ @@ -69,95 +69,105 @@ cd linux-%{KernelVer} perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = -%{release}.raspi.%{_target_cpu}/" Makefile -make ARCH=%{Arch} %{?_smp_mflags} bcm2711_defconfig +make ARCH=%{Arch} %{?_smp_mflags} O=output/v8 bcm2711_defconfig -make ARCH=%{Arch} %{?_smp_mflags} KERNELRELEASE=%{KernelVer} +make ARCH=%{Arch} %{?_smp_mflags} O=output/v8 KERNELRELEASE=%{KernelVer}-v8 + +make ARCH=%{Arch} %{?_smp_mflags} O=output/2712 bcm2712_defconfig + +make ARCH=%{Arch} %{?_smp_mflags} O=output/2712 KERNELRELEASE=%{KernelVer}-2712 %install cd linux-%{KernelVer} ## install linux - -make ARCH=%{Arch} INSTALL_MOD_PATH=$RPM_BUILD_ROOT modules_install KERNELRELEASE=%{KernelVer} -rm -rf $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/source $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build - mkdir -p $RPM_BUILD_ROOT/boot -TargetImage=$(make -s image_name) -TargetImage=${TargetImage%.*} -install -m 755 $TargetImage $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} -install -m 644 .config $RPM_BUILD_ROOT/boot/config-%{KernelVer} -install -m 644 System.map $RPM_BUILD_ROOT/boot/System.map-%{KernelVer} +rpi_version=("v8" "2712") +for rpi in "${rpi_version[@]}"; do + pushd output/$rpi + kernel_ver=%{KernelVer}-$rpi + TargetImage=$(make -s image_name) + make ARCH=%{Arch} INSTALL_MOD_PATH=$RPM_BUILD_ROOT modules_install KERNELRELEASE=$kernel_ver + install -m 755 $TargetImage $RPM_BUILD_ROOT/boot/vmlinuz-$kernel_ver + install -m 644 .config $RPM_BUILD_ROOT/boot/config-$kernel_ver + install -m 644 System.map $RPM_BUILD_ROOT/boot/System.map-$kernel_ver + rm -rf $RPM_BUILD_ROOT/lib/modules/$kernel_ver/source $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build + mkdir -p $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build + + ############ to do collect devel file ######### + # 1. Makefile And Kconfig, .config sysmbol + # 2. scrpits dir + # 3. .h file + find -type f \( -name "Makefile*" -o -name "Kconfig*" \) -exec cp --parents {} $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build \; + for f in Module.symvers System.map Module.markers .config;do + test -f $f || continue + cp $f $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build + done + + cp -a scripts $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build + if [ -d arch/%{Arch}/scripts ]; then + cp -a arch/%{Arch}/scripts $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/arch/%{_arch} || : + fi + if [ -f arch/%{Arch}/*lds ]; then + cp -a arch/%{Arch}/*lds $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/arch/%{_arch}/ || : + fi + find $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/scripts/ -name "*.o" -exec rm -rf {} \; + + if [ -d arch/%{Arch}/include ]; then + cp -a --parents arch/%{Arch}/include $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/ + fi + cp -a include $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/include + + if [ -f arch/%{Arch}/kernel/module.lds ]; then + cp -a --parents arch/%{Arch}/kernel/module.lds $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/ + fi + + # module.lds is moved to scripts by commit 596b0474d3d9 in linux 5.10. + if [ -f scripts/module.lds ]; then + cp -a --parents scripts/module.lds $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/ + fi + + # copy objtool for raspberrypi-kernel-devel (needed for building external modules) + if grep -q CONFIG_STACK_VALIDATION=y .config; then + mkdir -p $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/tools/objtool + cp -a tools/objtool/objtool $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/tools/objtool + fi + + popd + + %ifarch aarch64 + cp -a --parents arch/arm/include/asm $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/ + %endif + + # Make sure the Makefile and version.h have a matching timestamp so that + # external modules can be built + touch -r $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/Makefile $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/include/generated/uapi/linux/version.h + touch -r $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/.config $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/include/generated/autoconf.h + # for make prepare + if [ ! -f $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/include/config/auto.conf ];then + cp .config $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build/include/config/auto.conf + fi + + mkdir -p %{buildroot}/usr/src/kernels + mv $RPM_BUILD_ROOT/lib/modules/$kernel_ver/build $RPM_BUILD_ROOT/usr/src/kernels/$kernel_ver + + find $RPM_BUILD_ROOT/usr/src/kernels/$kernel_ver -name ".*.cmd" -exec rm -f {} \; + + pushd $RPM_BUILD_ROOT/lib/modules/$kernel_ver + ln -sf /usr/src/kernels/$kernel_ver build + ln -sf build source + popd +done + +pushd output/2712 mkdir -p $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/overlays install -m 644 $(find arch/%{Arch}/boot/dts/broadcom/ -name "*.dtb") $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/ install -m 644 $(find arch/%{Arch}/boot/dts/overlays/ -name "*.dtbo") $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/overlays/ if ls arch/%{Arch}/boot/dts/overlays/*.dtb > /dev/null 2>&1; then install -m 644 $(find arch/%{Arch}/boot/dts/overlays/ -name "*.dtb") $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/overlays/ fi -install -m 644 arch/%{Arch}/boot/dts/overlays/README $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/overlays/ - -mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build - -############ to do collect devel file ######### -# 1. Makefile And Kconfig, .config sysmbol -# 2. scrpits dir -# 3. .h file -find -type f \( -name "Makefile*" -o -name "Kconfig*" \) -exec cp --parents {} $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build \; -for f in Module.symvers System.map Module.markers .config;do - test -f $f || continue - cp $f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build -done - -cp -a scripts $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build -if [ -d arch/%{Arch}/scripts ]; then - cp -a arch/%{Arch}/scripts $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/arch/%{_arch} || : -fi -if [ -f arch/%{Arch}/*lds ]; then - cp -a arch/%{Arch}/*lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/arch/%{_arch}/ || : -fi -find $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/scripts/ -name "*.o" -exec rm -rf {} \; - -if [ -d arch/%{Arch}/include ]; then - cp -a --parents arch/%{Arch}/include $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/ -fi -cp -a include $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include - -if [ -f arch/%{Arch}/kernel/module.lds ]; then - cp -a --parents arch/%{Arch}/kernel/module.lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/ -fi - -# module.lds is moved to scripts by commit 596b0474d3d9 in linux 5.10. -if [ -f scripts/module.lds ]; then - cp -a --parents scripts/module.lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/ -fi - -%ifarch aarch64 - cp -a --parents arch/arm/include/asm $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/ -%endif - -# copy objtool for raspberrypi-kernel-devel (needed for building external modules) -if grep -q CONFIG_STACK_VALIDATION=y .config; then - mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/tools/objtool - cp -a tools/objtool/objtool $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/tools/objtool -fi - -# Make sure the Makefile and version.h have a matching timestamp so that -# external modules can be built -touch -r $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/Makefile $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/generated/uapi/linux/version.h -touch -r $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/.config $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/generated/autoconf.h -# for make prepare -if [ ! -f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/config/auto.conf ];then - cp .config $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/config/auto.conf -fi - -mkdir -p %{buildroot}/usr/src/kernels -mv $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build $RPM_BUILD_ROOT/usr/src/kernels/%{KernelVer} - -find $RPM_BUILD_ROOT/usr/src/kernels/%{KernelVer} -name ".*.cmd" -exec rm -f {} \; - -pushd $RPM_BUILD_ROOT/lib/modules/%{KernelVer} -ln -sf /usr/src/kernels/%{KernelVer} build -ln -sf build source +install -m 644 ../../arch/%{Arch}/boot/dts/overlays/README $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/overlays/ popd %postun @@ -184,14 +194,15 @@ else fi fi if [ "$version_old" != "0" ]; then - if [ -f /boot/vmlinuz-$version_old ] && [ -d /boot/dtb-$version_old ] && [ -d /lib/modules/$version_old ]; then + if [ -f /boot/vmlinuz-$version_old-v8 ] && [ -d /boot/dtb-$version_old ] && [ -d /lib/modules/$version_old-v8 ] && [ -f /boot/vmlinuz-$version_old-2712 ] && [ -d /lib/modules/$version_old-2712 ]; then ls /boot/dtb-$version_old/overlays/*.dtbo > /dev/null 2>&1 if [ "$?" == "0" ]; then ls /boot/dtb-$version_old/*.dtb > /dev/null 2>&1 if [ "$?" == "0" ]; then - rm -rf /boot/*.dtb /boot/overlays /boot/kernel8.img + rm -rf /boot/*.dtb /boot/overlays /boot/kernel8.img /boot/kernel_2712.img mkdir /boot/overlays - install -m 755 /boot/vmlinuz-$version_old /boot/kernel8.img + install -m 755 /boot/vmlinuz-$version_old-v8 /boot/kernel8.img + install -m 755 /boot/vmlinuz-$version_old-2712 /boot/kernel_2712.img for file in `ls /boot/dtb-$version_old/*.dtb 2>/dev/null` do if [ -f $file ]; then @@ -215,9 +226,10 @@ if [ "$version_old" != "0" ]; then fi %posttrans -rm -rf /boot/*.dtb /boot/overlays /boot/kernel8.img +rm -rf /boot/*.dtb /boot/overlays /boot/kernel8.img /boot/kernel_2712.img mkdir -p /boot/overlays -install -m 755 /boot/vmlinuz-%{KernelVer} /boot/kernel8.img +install -m 755 /boot/vmlinuz-%{KernelVer}-v8 /boot/kernel8.img +install -m 755 /boot/vmlinuz-%{KernelVer}-2712 /boot/kernel_2712.img for file in `ls /boot/dtb-%{KernelVer}/*.dtb 2>/dev/null` do if [ -f $file ]; then @@ -237,10 +249,16 @@ then fi if [ "$HARDLINK" != "no" -a -x /usr/sbin/hardlink ] then - (cd /usr/src/kernels/%{KernelVer} && + (pushd /usr/src/kernels/%{KernelVer}-v8 && /usr/bin/find . -type f | while read f; do hardlink -c /usr/src/kernels/*.oe*.*/$f $f - done) + done && + popd && + pushd /usr/src/kernels/%{KernelVer}-2712 && + /usr/bin/find . -type f | while read f; do + hardlink -c /usr/src/kernels/*.oe*.*/$f $f + done && + popd) fi %files @@ -250,16 +268,23 @@ fi /boot/System.map-* /boot/vmlinuz-* /boot/dtb-* -/lib/modules/%{KernelVer} +/lib/modules/%{KernelVer}-v8 +/lib/modules/%{KernelVer}-2712 %files devel %defattr (-, root, root) %doc -/lib/modules/%{KernelVer}/source -/lib/modules/%{KernelVer}/build -/usr/src/kernels/%{KernelVer} +/lib/modules/%{KernelVer}-v8/source +/lib/modules/%{KernelVer}-v8/build +/lib/modules/%{KernelVer}-2712/source +/lib/modules/%{KernelVer}-2712/build +/usr/src/kernels/%{KernelVer}-* %changelog +* Wed Dec 11 2024 Yafen Fang - 6.6.0-64.0.0.6 +- update kernel version to openEuler 6.6.0-64.0.0 +- add support for RPi 5 + * Wed May 29 2024 Yafen Fang - 6.6.0-28.0.0.5 - update kernel version to openEuler 6.6.0-28.0.0