bcm27xx: update to latest RPi patches
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Thu, 31 Oct 2024 09:09:44 +0000 (10:09 +0100)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Thu, 31 Oct 2024 12:44:23 +0000 (13:44 +0100)
The patches were generated from the RPi repo with the following command:
git format-patch v6.6.58..rpi-6.6.y

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
126 files changed:
target/linux/bcm27xx/bcm2708/config-6.6
target/linux/bcm27xx/bcm2711/config-6.6
target/linux/bcm27xx/bcm2712/config-6.6
target/linux/bcm27xx/modules/sound.mk
target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-0655-vc4-drm-Remove-the-clear-of-SCALER_DISPBKGND_FILL.patch
target/linux/bcm27xx/patches-6.6/950-0675-drm-vc4-Correct-address-offset-for-planes-with-src_-.patch
target/linux/bcm27xx/patches-6.6/950-0711-drm-vc4-Add-hvs_dlist_allocs-debugfs-function.patch
target/linux/bcm27xx/patches-6.6/950-0738-drm-vc4-Drop-planes-that-are-completely-off-screen.patch
target/linux/bcm27xx/patches-6.6/950-0740-drm-vc4-Free-the-dlist-alloc-immediately-if-it-never.patch
target/linux/bcm27xx/patches-6.6/950-0763-drm-vc4-Mop-and-moplet-have-different-register-offse.patch
target/linux/bcm27xx/patches-6.6/950-0829-vc4-hvs-Add-support-for-D0-register-changes.patch
target/linux/bcm27xx/patches-6.6/950-0830-vc4-hvs-Updates-to-support-D0-alpha-and-csc-changes.patch
target/linux/bcm27xx/patches-6.6/950-0833-drm-vc4-Add-2712-support-to-vc4_plane_async_set_fb.patch
target/linux/bcm27xx/patches-6.6/950-0834-drm-vc4-Fix-atomic_async_check-to-call-the-right-mod.patch
target/linux/bcm27xx/patches-6.6/950-0884-drm-vc4-Drop-planes-that-have-0-destination-size.patch
target/linux/bcm27xx/patches-6.6/950-0885-vc4-hvs-Support-fixed-alpha-correctly-on-2712D0.patch
target/linux/bcm27xx/patches-6.6/950-0902-vc4-hvs-Fix-lbm-size-calculation-for-yuv.patch
target/linux/bcm27xx/patches-6.6/950-0989-drm-vc4-Enable-bg_fill-if-there-are-no-planes-enable.patch
target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-1065-drm-vc4-Add-option-to-call-from-crtc-to-encoder-on-v.patch
target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-1168-fixup-mmc-restrict-posted-write-counts-for-SD-cards-.patch
target/linux/bcm27xx/patches-6.6/950-1199-drm-vc4-Disable-the-2pixel-clock-odd-timings-workaro.patch
target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch [new file with mode: 0644]

index a50596e45e62c267506e8b82d0dd5a9dc56acb80..4872e44642f8f0dc6f1f06d2868ffd1e5eac9427 100644 (file)
@@ -160,6 +160,7 @@ CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_FONT_8x16=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_SUPPORT=y
+CONFIG_FORCE_NR_CPUS=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
index 33458c27d725c27d0b3869a4c6847d967ef94fa0..270763549a199ebab96d8914dead54feb18a1f59 100644 (file)
@@ -176,6 +176,7 @@ CONFIG_DMA_BCM2835=y
 CONFIG_DMA_CMA=y
 CONFIG_DMA_DIRECT_REMAP=y
 CONFIG_DMA_ENGINE=y
+# CONFIG_DMA_NUMA_CMA is not set
 CONFIG_DMA_OF=y
 CONFIG_DMA_SHARED_BUFFER=y
 CONFIG_DMA_VIRTUAL_CHANNELS=y
@@ -221,6 +222,8 @@ CONFIG_FW_LOADER_SYSFS=y
 CONFIG_GCC10_NO_ARRAY_BOUNDS=y
 CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
 CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_NUMA=y
+CONFIG_GENERIC_ARCH_NUMA_EMULATION=y
 CONFIG_GENERIC_ARCH_TOPOLOGY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
@@ -331,6 +334,8 @@ CONFIG_MODULES_USE_ELF_RELA=y
 # CONFIG_MTD is not set
 CONFIG_MUTEX_SPIN_ON_OWNER=y
 CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
 CONFIG_NEED_SG_DMA_LENGTH=y
 CONFIG_NET_EGRESS=y
 CONFIG_NET_FLOW_LIMIT=y
@@ -340,11 +345,15 @@ CONFIG_NET_SELFTESTS=y
 CONFIG_NET_XGRESS=y
 CONFIG_NLS=y
 CONFIG_NLS_ASCII=y
+CONFIG_NODES_SHIFT=4
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_NO_HZ=y
 CONFIG_NO_HZ_COMMON=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=4
+CONFIG_NUMA=y
+# CONFIG_NUMA_BALANCING is not set
+CONFIG_NUMA_EMULATION=y
 CONFIG_NVMEM=y
 CONFIG_NVMEM_LAYOUTS=y
 CONFIG_NVMEM_RASPBERRYPI_OTP=y
@@ -358,6 +367,7 @@ CONFIG_OF_GPIO=y
 CONFIG_OF_IRQ=y
 CONFIG_OF_KOBJ=y
 CONFIG_OF_MDIO=y
+CONFIG_OF_NUMA=y
 CONFIG_OF_OVERLAY=y
 CONFIG_OF_RESOLVE=y
 CONFIG_PADATA=y
@@ -485,6 +495,7 @@ CONFIG_USB_UAS=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_PCI=y
 CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USE_PERCPU_NUMA_NODE_ID=y
 CONFIG_VCHIQ_CDEV=y
 CONFIG_VIDEO_CMDLINE=y
 CONFIG_VIDEO_DEV=y
index 734b19612bca37ab6f13baa518d2a76304ab7eee..a5eb6c4d0e1f1297cbcb4f4894649cca93ed0484 100644 (file)
@@ -218,6 +218,7 @@ CONFIG_DMA_BCM2835=y
 CONFIG_DMA_CMA=y
 CONFIG_DMA_DIRECT_REMAP=y
 CONFIG_DMA_ENGINE=y
+# CONFIG_DMA_NUMA_CMA is not set
 CONFIG_DMA_OF=y
 CONFIG_DMA_OPS=y
 CONFIG_DMA_SHARED_BUFFER=y
@@ -264,6 +265,8 @@ CONFIG_FW_LOADER_SYSFS=y
 CONFIG_GCC10_NO_ARRAY_BOUNDS=y
 CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
 CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_NUMA=y
+CONFIG_GENERIC_ARCH_NUMA_EMULATION=y
 CONFIG_GENERIC_ARCH_TOPOLOGY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
@@ -409,6 +412,8 @@ CONFIG_MMU_LAZY_TLB_REFCOUNT=y
 CONFIG_MODULES_USE_ELF_RELA=y
 CONFIG_MUTEX_SPIN_ON_OWNER=y
 CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
 CONFIG_NEED_SG_DMA_FLAGS=y
 CONFIG_NEED_SG_DMA_LENGTH=y
 CONFIG_NET_EGRESS=y
@@ -419,11 +424,15 @@ CONFIG_NET_SELFTESTS=y
 CONFIG_NET_XGRESS=y
 CONFIG_NLS=y
 CONFIG_NLS_ASCII=y
+CONFIG_NODES_SHIFT=4
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_NO_HZ=y
 CONFIG_NO_HZ_COMMON=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=4
+CONFIG_NUMA=y
+# CONFIG_NUMA_BALANCING is not set
+CONFIG_NUMA_EMULATION=y
 CONFIG_NVMEM=y
 CONFIG_NVMEM_LAYOUTS=y
 CONFIG_NVMEM_RASPBERRYPI_OTP=y
@@ -441,6 +450,7 @@ CONFIG_OF_IOMMU=y
 CONFIG_OF_IRQ=y
 CONFIG_OF_KOBJ=y
 CONFIG_OF_MDIO=y
+CONFIG_OF_NUMA=y
 CONFIG_OF_OVERLAY=y
 CONFIG_OF_RESOLVE=y
 CONFIG_PADATA=y
@@ -610,6 +620,7 @@ CONFIG_USB_UAS=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_PCI=y
 CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USE_PERCPU_NUMA_NODE_ID=y
 CONFIG_VCHIQ_CDEV=y
 CONFIG_VIDEO_CMDLINE=y
 CONFIG_VIDEO_DEV=y
index e61f07852b6a79bf7b55ce3d969173cb518e4895..989828e97ee9633ad4503bb1cfa918de672ca01e 100644 (file)
@@ -45,7 +45,8 @@ $(eval $(call KernelPackage,sound-soc-bcm2835-i2s))
 define KernelPackage/sound-soc-rpi-simple-soundcard
   TITLE:=Support for Raspberry Pi simple soundcards
   KCONFIG:= \
-    CONFIG_SND_RPI_SIMPLE_SOUNDCARD
+    CONFIG_SND_RPI_SIMPLE_SOUNDCARD \
+    CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC8X
   FILES:= \
     $(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-simple-soundcard.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-rpi-simple-soundcard)
@@ -526,6 +527,32 @@ endef
 $(eval $(call KernelPackage,sound-soc-googlevoicehat))
 
 
+define KernelPackage/sound-soc-hifiberry-adc
+  TITLE:=Support for HifiBerry ADC
+  KCONFIG:= \
+    CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC \
+    CONFIG_SND_RPI_HIFIBERRY_ADC \
+    CONFIG_SND_SOC_PCM186X_I2C
+  FILES:= \
+    $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-adc.ko \
+    $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm186x.ko \
+    $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm186x-i2c.ko
+  AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm186x snd-soc-pcm186x-i2c \
+    snd-soc-hifiberry-adc)
+  DEPENDS:= \
+    kmod-sound-soc-bcm2835-i2s \
+    +kmod-i2c-bcm2835 \
+    +kmod-regmap-i2c
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-hifiberry-adc/description
+  This package contains support for HifiBerry ADC
+endef
+
+$(eval $(call KernelPackage,sound-soc-hifiberry-adc))
+
+
 define KernelPackage/sound-soc-hifiberry-dac
   TITLE:=Support for HifiBerry DAC
   KCONFIG:= \
diff --git a/target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch b/target/linux/bcm27xx/patches-6.6/950-0058-Revert-Bluetooth-Always-request-for-user-confirmatio.patch
deleted file mode 100644 (file)
index 5e3446d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-From eaeca896d077e9e42866f7f7caae7b62211a0d0d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Mon, 1 Mar 2021 09:12:44 +0000
-Subject: [PATCH 0058/1085] Revert "Bluetooth: Always request for user
- confirmation for Just Works (LE SC)"
-
-This reverts commit ffee202a78c2980688bc5d2f7d56480e69a5e0c9.
-
-The commit "Bluetooth: Always request for user confirmation for Just
-Works" prevents BLE devices pairing in (at least) the Raspberry Pi OS
-GUI. After reverting it, pairing works again. Although this companion
-commit ("... (LE SC)") has not been demonstrated to be problematic,
-it follows the same logic and therefore could affect some use cases.
-
-If another solution to the problem is found then this reversion will
-be removed.
-
-See: https://github.com/raspberrypi/linux/issues/4139
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- net/bluetooth/smp.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
---- a/net/bluetooth/smp.c
-+++ b/net/bluetooth/smp.c
-@@ -2215,7 +2215,7 @@ mackey_and_ltk:
-       if (err)
-               return SMP_UNSPECIFIED;
--      if (smp->method == REQ_OOB) {
-+      if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
-               if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
-                       sc_dhkey_check(smp);
-                       SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
-@@ -2230,9 +2230,6 @@ mackey_and_ltk:
-       confirm_hint = 0;
- confirm:
--      if (smp->method == JUST_WORKS)
--              confirm_hint = 1;
--
-       err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
-                                       hcon->dst_type, passkey, confirm_hint);
-       if (err)
diff --git a/target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch b/target/linux/bcm27xx/patches-6.6/950-0320-spi-spidev-Restore-loading-from-Device-Tree.patch
deleted file mode 100644 (file)
index da1bbb7..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 2f223e0e4931486fbc32df3c89bc16ff1ca434bf Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Mon, 29 Nov 2021 12:14:49 +0000
-Subject: [PATCH 0320/1085] spi: spidev: Restore loading from Device Tree
-
-As happens occasionally, an upstream change has once again prevented
-spidev from being loaded via Device Tree. We now need "spidev" to be
-included in the new spi_device_id list, otherwise although the
-spidev driver gets loaded no /dev/spidev*.* entries will appear.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/spi/spidev.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/spi/spidev.c
-+++ b/drivers/spi/spidev.c
-@@ -699,6 +699,7 @@ static const struct file_operations spid
- static struct class *spidev_class;
- static const struct spi_device_id spidev_spi_ids[] = {
-+      { .name = "spidev" },
-       { .name = "bh2228fv" },
-       { .name = "dh2228fv" },
-       { .name = "jg10309-01" },
diff --git a/target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch b/target/linux/bcm27xx/patches-6.6/950-0635-drm-vc4-Assign-LBM-memory-during-atomic_flush.patch
deleted file mode 100644 (file)
index ccdae3d..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-From c7b98a63328a749d44b7580ee9baafc5d417e48f Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Thu, 31 Aug 2023 11:45:38 +0100
-Subject: [PATCH 0635/1085] drm/vc4: Assign LBM memory during atomic_flush.
-
-Avoid double buffering LBM allocations by making the
-allocation a single alloc per crtc at atomic_flush.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c |  2 +-
- drivers/gpu/drm/vc4/vc4_drv.h                 |  8 ++--
- drivers/gpu/drm/vc4/vc4_hvs.c                 | 47 ++++++++++++++++++-
- drivers/gpu/drm/vc4/vc4_plane.c               | 38 +++------------
- 4 files changed, 58 insertions(+), 37 deletions(-)
-
---- a/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c
-+++ b/drivers/gpu/drm/vc4/tests/vc4_test_lbm_size.c
-@@ -248,7 +248,7 @@ static void drm_vc4_test_vc4_lbm_size(st
-       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);
-+      KUNIT_EXPECT_EQ(test, vc4_plane_state->lbm_size, params->expected_lbm_size);
-       for (i = 0; i < 2; i++) {
-               KUNIT_EXPECT_EQ(test,
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -417,6 +417,8 @@ 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.
-        */
-@@ -442,9 +444,6 @@ struct vc4_plane_state {
-       bool is_unity;
-       bool is_yuv;
--      /* Our allocation in LBM for temporary storage during scaling. */
--      struct drm_mm_node lbm;
--
-       /* Our allocation in UPM for prefetching. */
-       struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES];
-@@ -635,6 +634,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)                                    \
---- a/drivers/gpu/drm/vc4/vc4_hvs.c
-+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
-@@ -1103,6 +1103,7 @@ int vc4_hvs_atomic_check(struct drm_crtc
-       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.)
-@@ -1111,6 +1112,8 @@ int vc4_hvs_atomic_check(struct drm_crtc
-               return -EINVAL;
-       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",
-@@ -1119,6 +1122,7 @@ int vc4_hvs_atomic_check(struct drm_crtc
-                              plane_dlist_count);
-               dlist_count += plane_dlist_count;
-+              lbm_count += vc4_plane_state->lbm_size;
-       }
-       dlist_count++; /* Account for SCALER_CTL0_END. */
-@@ -1132,6 +1136,8 @@ int vc4_hvs_atomic_check(struct drm_crtc
-       vc4_state->mm = alloc;
-+      /* FIXME: Check total lbm allocation here */
-+
-       return vc4_hvs_gamma_check(crtc, state);
- }
-@@ -1246,7 +1252,10 @@ void vc4_hvs_atomic_flush(struct drm_crt
-       bool debug_dump_regs = false;
-       bool enable_bg_fill = false;
-       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;
-@@ -1265,6 +1274,35 @@ void vc4_hvs_atomic_flush(struct drm_crt
-               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;
-@@ -1276,6 +1314,8 @@ void vc4_hvs_atomic_flush(struct drm_crt
-                       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
-@@ -1286,10 +1326,15 @@ void vc4_hvs_atomic_flush(struct drm_crt
-                                * 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;
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -288,7 +288,6 @@ struct drm_plane_state *vc4_plane_duplic
-       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++)
-@@ -320,14 +319,6 @@ void vc4_plane_destroy_state(struct drm_
-       struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
-       unsigned int i;
--      if (drm_mm_node_allocated(&vc4_state->lbm)) {
--              unsigned long irqflags;
--
--              spin_lock_irqsave(&hvs->mm_lock, irqflags);
--              drm_mm_remove_node(&vc4_state->lbm);
--              spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
--      }
--
-       for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
-               unsigned long irqflags;
-@@ -903,12 +894,13 @@ static int vc4_plane_allocate_lbm(struct
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
-       struct drm_plane *plane = state->plane;
-       struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
--      unsigned long irqflags;
-       u32 lbm_size;
-       lbm_size = vc4_lbm_size(state);
--      if (!lbm_size)
-+      if (!lbm_size) {
-+              vc4_state->lbm_size = 0;
-               return 0;
-+      }
-       /*
-        * NOTE: BCM2712 doesn't need to be aligned, since the size
-@@ -925,28 +917,10 @@ static int vc4_plane_allocate_lbm(struct
-       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
-        */
--      if (!drm_mm_node_allocated(&vc4_state->lbm)) {
--              int ret;
--
--              spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
--              ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
--                                               &vc4_state->lbm,
--                                               lbm_size, 1,
--                                               0, 0);
--              spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
--
--              if (ret) {
--                      drm_err(drm, "Failed to allocate LBM entry: %d\n", ret);
--                      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->lbm_size = lbm_size;
-       return 0;
- }
index 67d8ae272651a4c800084a54c197f4ea359da235..fa57c12cf62878212c2ef0e0f3255c58d8f98d72 100644 (file)
@@ -25,7 +25,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_hvs.c
 +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
-@@ -1349,27 +1349,25 @@ void vc4_hvs_atomic_flush(struct drm_crt
+@@ -1304,27 +1304,25 @@ void vc4_hvs_atomic_flush(struct drm_crt
        WARN_ON(!vc4_state->mm);
        WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size);
  
index 9eb1ddad93966a792365f02355bc0433c097f3e4..30c6271bc6f166d5deed25a58f8ccf41851e79bc 100644 (file)
@@ -22,7 +22,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1447,9 +1447,9 @@ static int vc4_plane_mode_set(struct drm
+@@ -1473,9 +1473,9 @@ static int vc4_plane_mode_set(struct drm
        vc4_state->ptr0_offset[0] = vc4_state->dlist_count;
  
        for (i = 0; i < num_planes; i++) {
@@ -34,7 +34,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
        }
  
        /* Pointer Context Word 0/1/2: Written by the HVS */
-@@ -1842,9 +1842,8 @@ static int vc6_plane_mode_set(struct drm
+@@ -1868,9 +1868,8 @@ static int vc6_plane_mode_set(struct drm
         * TODO: This only covers Raster Scan Order planes
         */
        for (i = 0; i < num_planes; i++) {
index c04a5bb0e6d4c2f2dff80a3579a8a20d5162862a..e8e93d5e80a88b7dc0a13ee206dfed62469816d6 100644 (file)
@@ -50,7 +50,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
  /* The filter kernel is composed of dwords each containing 3 9-bit
   * signed integers packed next to each other.
   */
-@@ -1596,6 +1626,8 @@ int vc4_hvs_debugfs_init(struct drm_mino
+@@ -1551,6 +1581,8 @@ int vc4_hvs_debugfs_init(struct drm_mino
  
        drm_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, NULL);
  
index 321be130dc51889798eed385ffc448e56585dce7..b8aa8dccfd5997c92b9646fbbe17f8324b620611 100644 (file)
@@ -25,7 +25,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1108,6 +1108,12 @@ static int vc4_plane_mode_set(struct drm
+@@ -1134,6 +1134,12 @@ static int vc4_plane_mode_set(struct drm
        width = vc4_state->src_w[0] >> 16;
        height = vc4_state->src_h[0] >> 16;
  
@@ -38,7 +38,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
        /* 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
-@@ -1623,6 +1629,12 @@ static int vc6_plane_mode_set(struct drm
+@@ -1649,6 +1655,12 @@ static int vc6_plane_mode_set(struct drm
        width = vc4_state->src_w[0] >> 16;
        height = vc4_state->src_h[0] >> 16;
  
@@ -51,7 +51,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
        /* 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
-@@ -1994,6 +2006,9 @@ int vc4_plane_atomic_check(struct drm_pl
+@@ -2020,6 +2032,9 @@ int vc4_plane_atomic_check(struct drm_pl
        if (ret)
                return ret;
  
index 3782d53e346ba8b0099caca60118175105169a08..dced86878d1eb82c206b02238247873cf7b6fd9e 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_drv.h
 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -667,6 +667,7 @@ struct vc4_hvs_dlist_allocation {
+@@ -665,6 +665,7 @@ struct vc4_hvs_dlist_allocation {
        struct drm_mm_node mm_node;
        unsigned int channel;
        u8 target_frame_count;
@@ -46,7 +46,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
                spin_lock_irqsave(&hvs->mm_lock, flags);
                vc4_hvs_free_dlist_entry_locked(hvs, alloc);
                spin_unlock_irqrestore(&hvs->mm_lock, flags);
-@@ -1201,6 +1204,7 @@ static void vc4_hvs_install_dlist(struct
+@@ -1195,6 +1198,7 @@ static void vc4_hvs_install_dlist(struct
                return;
  
        WARN_ON(!vc4_state->mm);
index ccf84b313c994f3a38b912ec6c2a94bd86e884ea..2340240218e2ceec700c1b89753a13e589f2268a 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_drv.h
 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -549,6 +549,7 @@ struct vc4_crtc_data {
+@@ -550,6 +550,7 @@ struct vc4_crtc_data {
  struct vc4_txp_data {
        struct vc4_crtc_data    base;
        enum vc4_encoder_type encoder_type;
index 1bc75773b798eda870028d9e549b894ffe7848fe..3d13a6a09c39281f5bfebfda9b56b503b49bfe6a 100644 (file)
@@ -54,7 +54,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
  
        unsigned int irq;
  
-@@ -714,6 +715,12 @@ struct vc4_crtc_state {
+@@ -712,6 +713,12 @@ struct vc4_crtc_state {
                writel(val, hvs->regs + (offset));                                      \
        } while (0)
  
@@ -244,7 +244,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
  
  out:
        drm_dev_exit(idx);
-@@ -1227,8 +1286,8 @@ static void vc4_hvs_install_dlist(struct
+@@ -1221,8 +1280,8 @@ static void vc4_hvs_install_dlist(struct
  
        if (vc4->gen >= VC4_GEN_6)
                HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel),
@@ -255,7 +255,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
        else
                HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
                          vc4_state->mm->mm_node.start);
-@@ -1427,11 +1486,11 @@ void vc4_hvs_atomic_flush(struct drm_crt
+@@ -1382,11 +1441,11 @@ void vc4_hvs_atomic_flush(struct drm_crt
                if (enable_bg_fill)
                        HVS_WRITE(SCALER6_DISPX_CTRL1(channel),
                                  HVS_READ(SCALER6_DISPX_CTRL1(channel)) |
@@ -269,7 +269,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
        } else {
                /* we can actually run with a lower core clock when background
                 * fill is enabled on VC4_GEN_5 so leave it enabled always.
-@@ -1701,7 +1760,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
+@@ -1656,7 +1715,7 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
                 * access a register. Use a plausible size then.
                 */
                if (!kunit_get_current_test())
@@ -278,7 +278,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
                else
                        dlist_size = 4096;
  
-@@ -1935,14 +1994,17 @@ static int vc6_hvs_hw_init(struct vc4_hv
+@@ -1890,14 +1949,17 @@ static int vc6_hvs_hw_init(struct vc4_hv
        const struct vc6_csc_coeff_entry *coeffs;
        unsigned int i;
  
@@ -300,7 +300,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
  
        for (i = 0; i < 6; i++) {
                coeffs = &csc_coeffs[i / 3][i % 3];
-@@ -2041,21 +2103,21 @@ static int vc4_hvs_cob_init(struct vc4_h
+@@ -1996,21 +2058,21 @@ static int vc4_hvs_cob_init(struct vc4_h
                reg = 0;
                top = 3840;
  
@@ -325,7 +325,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
                          VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
                          VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
                break;
-@@ -2086,7 +2148,10 @@ static int vc4_hvs_bind(struct device *d
+@@ -2041,7 +2103,10 @@ static int vc4_hvs_bind(struct device *d
  
        hvs->regset.base = hvs->regs;
  
@@ -337,7 +337,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
                hvs->regset.regs = vc6_hvs_regs;
                hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs);
        } else {
-@@ -2253,6 +2318,7 @@ static void vc4_hvs_dev_remove(struct pl
+@@ -2208,6 +2273,7 @@ static void vc4_hvs_dev_remove(struct pl
  static const struct of_device_id vc4_hvs_dt_match[] = {
        { .compatible = "brcm,bcm2711-hvs" },
        { .compatible = "brcm,bcm2712-hvs" },
index 0a38601048fe745a5eba9d2dfbf486eec2e81acb..d88e6a744cda160ebc96689adc92f562dee68d7c 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_hvs.c
 +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
-@@ -1933,6 +1933,17 @@ static int vc4_hvs_hw_init(struct vc4_hv
+@@ -1888,6 +1888,17 @@ static int vc4_hvs_hw_init(struct vc4_hv
  #define CFC1_N_MA_CSC_COEFF_C23(x)    (0xa03c + ((x) * 0x3000))
  #define CFC1_N_MA_CSC_COEFF_C24(x)    (0xa040 + ((x) * 0x3000))
  
@@ -34,7 +34,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
  /* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3
   * output components
   */
-@@ -2003,31 +2014,43 @@ static int vc6_hvs_hw_init(struct vc4_hv
+@@ -1958,31 +1969,43 @@ static int vc6_hvs_hw_init(struct vc4_hv
        HVS_WRITE(SCALER6(PRI_MAP0), 0xffffffff);
        HVS_WRITE(SCALER6(PRI_MAP1), 0xffffffff);
  
@@ -104,7 +104,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
        return 0;
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1054,6 +1054,12 @@ static u32 vc4_hvs5_get_alpha_blend_mode
+@@ -1080,6 +1080,12 @@ static u32 vc4_hvs5_get_alpha_blend_mode
  
        WARN_ON_ONCE(vc4->gen != VC4_GEN_5 && vc4->gen != VC4_GEN_6);
  
@@ -117,7 +117,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
        if (!state->fb->format->has_alpha)
                return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,
                                     SCALER5_CTL2_ALPHA_MODE);
-@@ -1569,14 +1575,13 @@ static int vc4_plane_mode_set(struct drm
+@@ -1595,14 +1601,13 @@ static int vc4_plane_mode_set(struct drm
  static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state)
  {
        struct drm_plane_state *state = &vc4_state->base;
@@ -133,7 +133,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
                /* CSC pre-loaded with:
                 * 0 = BT601 limited range
                 * 1 = BT709 limited range
-@@ -1590,8 +1595,15 @@ static u32 vc6_plane_get_csc_mode(struct
+@@ -1616,8 +1621,15 @@ static u32 vc6_plane_get_csc_mode(struct
                if (color_range > DRM_COLOR_YCBCR_FULL_RANGE)
                        color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
  
index 46a66f4c59de730e65d5041b3d0d50b060b6972f..423e5b63c94130f49445f77f2a38e65f33f5812d 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1877,7 +1877,7 @@ static int vc6_plane_mode_set(struct drm
+@@ -1903,7 +1903,7 @@ static int vc6_plane_mode_set(struct drm
                                 * The UPM buffer will be allocated in
                                 * vc6_plane_allocate_upm().
                                 */
@@ -26,7 +26,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
                                              SCALER6_PTR0_UPPER_ADDR));
  
                /* Pointer Word 1 */
-@@ -2079,7 +2079,8 @@ void vc4_plane_async_set_fb(struct drm_p
+@@ -2105,7 +2105,8 @@ void vc4_plane_async_set_fb(struct drm_p
  {
        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);
@@ -36,7 +36,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
        int idx;
  
        if (!drm_dev_enter(plane->dev, &idx))
-@@ -2089,19 +2090,38 @@ void vc4_plane_async_set_fb(struct drm_p
+@@ -2115,19 +2116,38 @@ void vc4_plane_async_set_fb(struct drm_p
         * because this is only called on the primary plane.
         */
        WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
index 07a36b16928c98706e1e8729b4d84aa1021b41b8..49d2129c84196e6dc46eddff5915886137a9f204 100644 (file)
@@ -19,7 +19,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -2205,11 +2205,15 @@ static int vc4_plane_atomic_async_check(
+@@ -2231,11 +2231,15 @@ static int vc4_plane_atomic_async_check(
  {
        struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
                                                                                 plane);
index 3e4bed22d4a4f296cbb2ab5ea1554c3a81966c23..3796a923a8e63fecfd0bb6feec9f0752da768273 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1114,7 +1114,7 @@ static int vc4_plane_mode_set(struct drm
+@@ -1140,7 +1140,7 @@ static int vc4_plane_mode_set(struct drm
        width = vc4_state->src_w[0] >> 16;
        height = vc4_state->src_h[0] >> 16;
  
@@ -25,7 +25,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
                /* 0 source size probably means the plane is offscreen */
                vc4_state->dlist_initialized = 1;
                return 0;
-@@ -1641,8 +1641,10 @@ static int vc6_plane_mode_set(struct drm
+@@ -1667,8 +1667,10 @@ static int vc6_plane_mode_set(struct drm
        width = vc4_state->src_w[0] >> 16;
        height = vc4_state->src_h[0] >> 16;
  
@@ -38,7 +38,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
                vc4_state->dlist_initialized = 1;
                return 0;
        }
-@@ -2018,7 +2020,8 @@ int vc4_plane_atomic_check(struct drm_pl
+@@ -2044,7 +2046,8 @@ int vc4_plane_atomic_check(struct drm_pl
        if (ret)
                return ret;
  
index 0100b20df538594ab14d516d39deec4350c37472..3147ac297f26a6a00c18851750f35241f726a071 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -1079,6 +1079,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode
+@@ -1105,6 +1105,21 @@ static u32 vc4_hvs5_get_alpha_blend_mode
        }
  }
  
@@ -38,7 +38,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
  /* Writes out a full display list for an active plane to the plane's
   * private dlist state.
   */
-@@ -1824,7 +1839,7 @@ static int vc6_plane_mode_set(struct drm
+@@ -1850,7 +1865,7 @@ static int vc6_plane_mode_set(struct drm
        vc4_dlist_write(vc4_state,
                        SCALER6_CTL0_VALID |
                        VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) |
index 12f762ac91f83dc7d66f60d56837eba22473c67a..80724fd6ef19f1e26549ff44447890e31fd0d209 100644 (file)
@@ -18,7 +18,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_plane.c
 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -733,7 +733,7 @@ static unsigned int vc4_lbm_channel_size
+@@ -742,7 +742,7 @@ static unsigned int vc4_lbm_channel_size
        if (!components)
                return 0;
  
index addbb3691f0802c90a7e4635d67042e7d42e42cc..10d7f571194fc98d7340904e63af4bab2331bfcf 100644 (file)
@@ -19,12 +19,12 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 
 --- a/drivers/gpu/drm/vc4/vc4_hvs.c
 +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
-@@ -1406,7 +1406,7 @@ void vc4_hvs_atomic_flush(struct drm_crt
+@@ -1400,7 +1400,7 @@ void vc4_hvs_atomic_flush(struct drm_crt
        struct drm_plane *plane;
        struct vc4_plane_state *vc4_plane_state;
        bool debug_dump_regs = false;
 -      bool enable_bg_fill = false;
 +      bool enable_bg_fill = true;
        u32 __iomem *dlist_start, *dlist_next;
-       unsigned long irqflags;
        unsigned int zpos = 0;
+       bool found = false;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch b/target/linux/bcm27xx/patches-6.6/950-1019-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch
deleted file mode 100644 (file)
index 73a6b70..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From 43730828eca754b4b527d79fc5a1d3ff50c50481 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.com>
-Date: Mon, 8 Apr 2024 16:09:52 +0100
-Subject: [PATCH 1019/1085] drivers: mmc: disable write-caching on Samsung 2023
- model year SD cards
-
-Samsung EVO Plus, Pro Plus and Evo Ultimate cards of this era appear to
-have a broken cache-flush implementation when operating in CQ mode.
-
-Unfortunately the cards seem to use a separate CID name string for every
-variant and capacity, so nobble the cache feature for this MANFID, OEMID
-and year. Turning this off seems to have negligible impact on
-random-write throughput in non-CQ mode.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
----
- drivers/mmc/core/card.h   | 1 +
- drivers/mmc/core/quirks.h | 8 ++++++++
- 2 files changed, 9 insertions(+)
-
---- a/drivers/mmc/core/card.h
-+++ b/drivers/mmc/core/card.h
-@@ -84,6 +84,7 @@ struct mmc_fixup {
- #define CID_MANFID_TOSHIBA      0x11
- #define CID_MANFID_MICRON       0x13
- #define CID_MANFID_SAMSUNG      0x15
-+#define CID_MANFID_SAMSUNG_SD 0x1b
- #define CID_MANFID_APACER       0x27
- #define CID_MANFID_KINGSTON     0x70
- #define CID_MANFID_HYNIX      0x90
---- a/drivers/mmc/core/quirks.h
-+++ b/drivers/mmc/core/quirks.h
-@@ -25,6 +25,14 @@ static const struct mmc_fixup __maybe_un
-                  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.
-+       */
-+      _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SAMSUNG_SD, 0x534d, 2023, 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
- };
index 8137b10592d388d9e2821efd27420c3bc1c1ce33..d806631555f7d8e39909bfd1af6d86e33eea2b3e 100644 (file)
@@ -50,7 +50,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
  }
 --- a/drivers/gpu/drm/vc4/vc4_drv.h
 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -503,6 +503,7 @@ struct vc4_encoder {
+@@ -504,6 +504,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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch b/target/linux/bcm27xx/patches-6.6/950-1115-mmc-sd-halt-CQHCI-before-issuing-a-cache-flush-comma.patch
deleted file mode 100644 (file)
index 3f01a7b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From 8e40644b272a4ddc9d3b58b4373dffcef02d1b63 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.com>
-Date: Tue, 4 Jun 2024 13:21:47 +0100
-Subject: [PATCH 1115/1135] mmc: sd: halt CQHCI before issuing a cache flush
- command
-
-SD cards perform cache flushes by a CMD49 extension register write -
-which needs to be started from the SDHCI command/argument registers and
-not a CQHCI slot.
-
-Host access to SD/CQ registers should be exclusive to one or the other,
-so issue a halt before doing the command.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
----
- drivers/mmc/core/sd.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/mmc/core/sd.c
-+++ b/drivers/mmc/core/sd.c
-@@ -1265,6 +1265,14 @@ static int sd_flush_cache(struct mmc_hos
-       reg_buf = card->ext_reg_buf;
-       /*
-+       * Flushing requires sending CMD49 (adtc), which can't be done as a DCMD
-+       * and conflicts with CQHCI - temporarily turn CQE off to use the SDHCI
-+       * command/argument registers.
-+       */
-+      if (host->cqe_on)
-+              host->cqe_ops->cqe_off(host);
-+
-+      /*
-        * Set Flush Cache at bit 0 in the performance enhancement register at
-        * 261 bytes offset.
-        */
index 4f1d02c74daca60ff2fc1196daa8dad874044099..b4f30b4b3c4666d546a0aafe580175ef669a71c4 100644 (file)
@@ -60,7 +60,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
        }
  
        card->ext_perf.fno = fno;
-@@ -1383,6 +1384,7 @@ retry:
+@@ -1375,6 +1376,7 @@ retry:
  
                card->ocr = ocr;
                card->type = MMC_TYPE_SD;
index 78806c2b155bd7864154eb1393707e2ae56fa7d5..ea64afd5f9fdf75a2818b98630db0f05262a91d9 100644 (file)
@@ -135,7 +135,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
        },
 --- a/drivers/gpu/drm/vc4/vc4_drv.h
 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -569,6 +569,8 @@ struct vc4_pv_data {
+@@ -570,6 +570,8 @@ struct vc4_pv_data {
  
        /* Number of pixels output per clock period */
        u8 pixels_per_clock;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1208-DTS-bcm2712-enable-SD-slot-CQE-by-default-on-Pi-5.patch
deleted file mode 100644 (file)
index 16e7603..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From 216df57950849f905c398904e7d6cbdf278b5717 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.com>
-Date: Mon, 5 Aug 2024 11:28:36 +0100
-Subject: [PATCH 1208/1215] DTS: bcm2712: enable SD slot CQE by default on Pi 5
-
-The corresponding driver implementation has seen sufficient testing,
-so enable by default. Retain the dtparam so it can be turned off for test.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
----
- arch/arm/boot/dts/overlays/README                | 6 +++---
- arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 +
- 2 files changed, 4 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -378,9 +378,9 @@ Params:
-                                 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
---- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
-+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
-@@ -363,6 +363,7 @@ dpi_16bit_gpio2:        &rp1_dpi_16bit_g
-       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";
diff --git a/target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch b/target/linux/bcm27xx/patches-6.6/950-1218-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch
new file mode 100644 (file)
index 0000000..272f711
--- /dev/null
@@ -0,0 +1,27 @@
+From ad2babc6596ba4f500454a4eaa607f3b49fcbcbe Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 7 Aug 2024 17:41:31 +0100
+Subject: [PATCH 1218/1350] Bluetooth: hci_sync: Fix crash on NULL parent
+
+Although later functions can handle a NULL fwnode, fwnode can't handle
+being passed a NULL pointer.
+
+See: https://github.com/raspberrypi/linux/issues/6305
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ net/bluetooth/hci_sync.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -4861,7 +4861,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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch b/target/linux/bcm27xx/patches-6.6/950-1219-overlays-add-overlay-for-generic-I2S-clock-master-DA.patch
new file mode 100644 (file)
index 0000000..8fbde27
--- /dev/null
@@ -0,0 +1,96 @@
+From 209e8a3e6646f25abb352fd5a8a4c2e855b1e952 Mon Sep 17 00:00:00 2001
+From: Adrian Figueroa <elagil@takanome.de>
+Date: Wed, 14 Aug 2024 20:00:12 +0200
+Subject: [PATCH 1219/1350] overlays: add overlay for generic I2S clock-master
+ DAC
+
+Adds an overlay for supporting a generic I2S DAC that
+acts as the clock master on the bus.
+The data format is 32 bit stereo.
+
+Signed-off-by: Adrian Figueroa <elagil@takanome.de>
+---
+ arch/arm/boot/dts/overlays/Makefile           |  1 +
+ arch/arm/boot/dts/overlays/README             |  6 +++
+ .../dts/overlays/i2s-master-dac-overlay.dts   | 50 +++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2s-master-dac-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -125,6 +125,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       i2c6.dtbo \
+       i2s-dac.dtbo \
+       i2s-gpio28-31.dtbo \
++      i2s-master-dac.dtbo \
+       ilitek251x.dtbo \
+       imx219.dtbo \
+       imx258.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2633,6 +2633,12 @@ Load:   dtoverlay=i2s-gpio28-31
+ Params: <None>
++Name:   i2s-master-dac
++Info:   Configures a generic I2S DAC soundcard that acts as a clock master.
++Load:   dtoverlay=i2s-master-dac
++Params: <None>
++
++
+ Name:   ilitek251x
+ Info:   Enables I2C connected Ilitek 251x multiple touch controller using
+         GPIO 4 (pin 7 on GPIO header) for interrupt.
+--- /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/target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch b/target/linux/bcm27xx/patches-6.6/950-1220-ASoC-DACplusADCPro-put-ADC-control-definitions-in-he.patch
new file mode 100644 (file)
index 0000000..6de4528
--- /dev/null
@@ -0,0 +1,275 @@
+From 15ca476264094b25d0a210109a061192a468117b Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+Date: Thu, 15 Aug 2024 16:08:14 +0200
+Subject: [PATCH 1220/1350] ASoC: DACplusADCPro - put ADC control definitions
+ in header file
+
+For easier maintenance all ADC ALSA-Kcontrols and the respective
+definitions are placed into a new header file that is included
+by the existing DAC+ADC Pro driver and a new, soon to be
+released ADC only board driver using the same controls.
+
+Signed-off-by: j-schambacher <joerg@hifiberry.com>
+---
+ sound/soc/bcm/hifiberry_adc_controls.h  | 128 ++++++++++++++++++++++++
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 110 +-------------------
+ 2 files changed, 129 insertions(+), 109 deletions(-)
+ create mode 100644 sound/soc/bcm/hifiberry_adc_controls.h
+
+--- /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 <joerg@hifiberry.com>
++ *            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]),
++};
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -37,6 +37,7 @@
+ #include "../codecs/pcm512x.h"
+ #include "../codecs/pcm186x.h"
++#include "hifiberry_adc_controls.h"
+ #define HIFIBERRY_DACPRO_NOCLOCK 0
+ #define HIFIBERRY_DACPRO_CLK44EN 1
+@@ -57,115 +58,6 @@ static bool snd_rpi_hifiberry_is_dacpro;
+ 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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1222-drm-rp1-rp1-dsi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch
new file mode 100644 (file)
index 0000000..3f4be4c
--- /dev/null
@@ -0,0 +1,48 @@
+From 9c5d91f6b938c23065ddc21c8654c5e222c35687 Mon Sep 17 00:00:00 2001
+From: Jan Kehren <jan.kehren@emteria.com>
+Date: Fri, 16 Aug 2024 13:47:50 +0000
+Subject: [PATCH 1222/1350] drm: rp1: rp1-dsi: Add DRM_FORMAT_ARGB8888 and
+ DRM_FORMAT_ABGR8888
+
+Android requires this.
+As the underlying hardware doesn't support alpha blending,
+we ignore the alpha value.
+
+Signed-off-by: Jan Kehren <jan.kehren@emteria.com>
+---
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c     |  2 ++
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 12 ++++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
+@@ -229,6 +229,8 @@ static const struct drm_mode_config_func
+ 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
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c
+@@ -247,6 +247,18 @@ static const struct rp1dsi_ipixfmt my_fo
+               .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),
diff --git a/target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1223-drm-rp1-rp1-dpi-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch
new file mode 100644 (file)
index 0000000..a24a0e9
--- /dev/null
@@ -0,0 +1,48 @@
+From 9f0523de1b7ef122fae527326372a4ab5aa42fa6 Mon Sep 17 00:00:00 2001
+From: Jan Kehren <jan.kehren@emteria.com>
+Date: Tue, 20 Aug 2024 08:08:50 +0000
+Subject: [PATCH 1223/1350] drm: rp1: rp1-dpi: Add DRM_FORMAT_ARGB8888 and
+ DRM_FORMAT_ABGR8888
+
+Android requires this.
+As the underlying hardware doesn't support alpha blending,
+we ignore the alpha value.
+
+Signed-off-by: Jan Kehren <jan.kehren@emteria.com>
+---
+ drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c    |  2 ++
+ drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 12 ++++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
+@@ -260,6 +260,8 @@ static struct drm_driver rp1dpi_driver =
+ 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
+--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
+@@ -258,6 +258,18 @@ static const struct rp1dpi_ipixfmt my_fo
+         .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),
diff --git a/target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch b/target/linux/bcm27xx/patches-6.6/950-1224-drm-rp1-rp1-vec-Add-DRM_FORMAT_ARGB8888-and-DRM_FORM.patch
new file mode 100644 (file)
index 0000000..4c671cb
--- /dev/null
@@ -0,0 +1,48 @@
+From 29f7f01091f9aaa6b0c45f5c2e3db1792d381e9d Mon Sep 17 00:00:00 2001
+From: Jan Kehren <jan.kehren@emteria.com>
+Date: Tue, 20 Aug 2024 08:16:06 +0000
+Subject: [PATCH 1224/1350] drm: rp1: rp1-vec: Add DRM_FORMAT_ARGB8888 and
+ DRM_FORMAT_ABGR8888
+
+Android requires this.
+As the underlying hardware doesn't support alpha blending,
+we ignore the alpha value.
+
+Signed-off-by: Jan Kehren <jan.kehren@emteria.com>
+---
+ drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c    |  2 ++
+ drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 12 ++++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
+@@ -420,6 +420,8 @@ static const struct drm_mode_config_func
+ 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
+--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
+@@ -63,6 +63,18 @@ static const struct rp1vec_ipixfmt my_fo
+               .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),
diff --git a/target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch b/target/linux/bcm27xx/patches-6.6/950-1225-drm-vc4-Add-a-delay-after-disabling-hdmi-phy-output.patch
new file mode 100644 (file)
index 0000000..b00330b
--- /dev/null
@@ -0,0 +1,34 @@
+From d984fd8907736d37656c558e213cfe087e43a7ce Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Mon, 12 Aug 2024 13:31:58 +0100
+Subject: [PATCH 1225/1350] drm/vc4: Add a delay after disabling hdmi phy
+ output
+
+There appears to be a requirement for some devices
+(I'm testing with a 8K VRROOM 40Gbps HDMI switch)
+for a measable delay between removing the hdmi phy output from
+the old mode, to enabling the hdmi phy output for the new mode.
+
+Without the delay, a mode switch has a small change of getting a permanent
+'no signal', which requires a subsequent mode switch or a unplug/replug
+to redetect.
+
+Switching between 4kp24/25/30 modes fails about 5% of time in my testing.
+
+Add a delay to make it impossible to switch faster than this.
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -668,6 +668,7 @@ static void vc4_crtc_atomic_disable(stru
+        * someone was waiting it.
+        */
+       vc4_crtc_send_vblank(crtc);
++      msleep(20);
+ }
+ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch b/target/linux/bcm27xx/patches-6.6/950-1226-drm-vc4-Implement-vc6_hdmi_phy_disable.patch
new file mode 100644 (file)
index 0000000..527e815
--- /dev/null
@@ -0,0 +1,25 @@
+From aa54ce17dc3a19eaf26f9c17c05a18aabcac90b0 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Tue, 13 Aug 2024 16:13:16 +0100
+Subject: [PATCH 1226/1350] drm/vc4: Implement vc6_hdmi_phy_disable
+
+The body of this function was missing so we don't reset the phy
+when disabling it.
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
+@@ -1197,4 +1197,9 @@ void vc6_hdmi_phy_init(struct vc4_hdmi *
+ 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/target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch b/target/linux/bcm27xx/patches-6.6/950-1227-drm-vc4-Also-power-down-the-PLL-core-when-resetting-.patch
new file mode 100644 (file)
index 0000000..67df065
--- /dev/null
@@ -0,0 +1,35 @@
+From 3d21dabd055ca064880e775892a10c5e69fdf5e9 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Tue, 13 Aug 2024 17:18:51 +0100
+Subject: [PATCH 1227/1350] drm/vc4: Also power down the PLL core when
+ resetting PHY
+
+The current reset code doesn't actually stop the hdmi output.
+That makes it difficult for displays to handle a mode set.
+
+Powering down the PLL does actually remove the hdmi signal
+and makes mode sets more reliable
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
+@@ -137,6 +137,7 @@
+ #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)
+@@ -947,6 +948,7 @@ static void vc6_hdmi_reset_phy(struct vc
+       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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch b/target/linux/bcm27xx/patches-6.6/950-1228-ASoC-add-driver-for-new-HiFiBerry-ADC-only-board-s.patch
new file mode 100644 (file)
index 0000000..099d37e
--- /dev/null
@@ -0,0 +1,228 @@
+From 784ef64631be19ef45a597e618c04a0f8b041307 Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+Date: Tue, 20 Aug 2024 10:08:27 +0200
+Subject: [PATCH 1228/1350] ASoC: add driver for new HiFiBerry ADC only
+ board(s)
+
+Adds the driver for the soon to be released first ADC only board.
+It includes the same ADC controls as used by the DAC+ADC Pro driver.
+
+Signed-off-by: j-schambacher <joerg@hifiberry.com>
+---
+ sound/soc/bcm/Kconfig         |   7 ++
+ sound/soc/bcm/Makefile        |   2 +
+ sound/soc/bcm/hifiberry_adc.c | 174 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 183 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_adc.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -39,6 +39,13 @@ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SO
+       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.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DAC
+         tristate "Support for HifiBerry DAC and DAC8X"
+         select SND_SOC_PCM5102A
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) +
+ 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
+@@ -51,6 +52,7 @@ snd-soc-chipdip-dac-objs := chipdip-dac.
+ 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
+--- /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 <joerg@hifiberry.com>
++ *            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 <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/tlv.h>
++
++#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 <joerg@hifiberry.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry ADC");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch b/target/linux/bcm27xx/patches-6.6/950-1229-overlays-Add-overlay-for-Hifiberry-ADC.patch
new file mode 100644 (file)
index 0000000..b1e7631
--- /dev/null
@@ -0,0 +1,100 @@
+From 2f656dc533b65ae7f23527c3dc176efa92add105 Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+Date: Tue, 20 Aug 2024 10:24:10 +0200
+Subject: [PATCH 1229/1350] overlays: Add overlay for Hifiberry ADC
+
+Adds the DT overlay for the HiFiBerry ADC.
+
+Signed-off-by: j-schambacher <joerg@hifiberry.com>
+---
+ arch/arm/boot/dts/overlays/Makefile           |  1 +
+ arch/arm/boot/dts/overlays/README             |  7 +++
+ .../dts/overlays/hifiberry-adc-overlay.dts    | 45 +++++++++++++++++++
+ sound/soc/bcm/Kconfig                         |  1 +
+ 4 files changed, 54 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -85,6 +85,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       hd44780-i2c-lcd.dtbo \
+       hd44780-lcd.dtbo \
+       hdmi-backlight-hwhack-gpio.dtbo \
++      hifiberry-adc.dtbo \
+       hifiberry-amp.dtbo \
+       hifiberry-amp100.dtbo \
+       hifiberry-amp3.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1771,6 +1771,13 @@ Params: gpio_pin                GPIO pin
+                                 expects a high to switch it on.
++Name:   hifiberry-adc
++Info:   Configures the HifiBerry ADC audio card
++Load:   dtoverlay=hifiberry-adc,<param>=<val>
++Params: leds_off                If set to 'true' the onboard indicator LED
++                                is switched off at all times.
++
++
+ Name:   hifiberry-amp
+ Info:   Configures the HifiBerry Amp and Amp+ audio cards
+ Load:   dtoverlay=hifiberry-amp
+--- /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?";
++      };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -45,6 +45,7 @@ config SND_BCM2708_SOC_HIFIBERRY_ADC
+         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_DAC
+         tristate "Support for HifiBerry DAC and DAC8X"
diff --git a/target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch b/target/linux/bcm27xx/patches-6.6/950-1232-spi-spidev-Restore-loading-from-Device-Tree.patch
new file mode 100644 (file)
index 0000000..8384559
--- /dev/null
@@ -0,0 +1,25 @@
+From ba0f2212e0e100ee16bdde76b7efca6bb8ee9446 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 29 Nov 2021 12:14:49 +0000
+Subject: [PATCH 1232/1350] spi: spidev: Restore loading from Device Tree
+
+As happens occasionally, an upstream change has once again prevented
+spidev from being loaded via Device Tree. We now need "spidev" to be
+included in the new spi_device_id list, otherwise although the
+spidev driver gets loaded no /dev/spidev*.* entries will appear.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spidev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -711,6 +711,7 @@ static const struct spi_device_id spidev
+       { .name = "spi-authenta" },
+       { .name = "em3581" },
+       { .name = "si3210" },
++      { .name = "spidev" },
+       {},
+ };
+ MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch b/target/linux/bcm27xx/patches-6.6/950-1233-drivers-drm-rp1-dsi-Implement-more-DSI-options-and-f.patch
new file mode 100644 (file)
index 0000000..e906ad8
--- /dev/null
@@ -0,0 +1,242 @@
+From e596d70725ca70113d39d9366d7b4d3e492f6449 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Wed, 31 Jul 2024 19:05:29 +0100
+Subject: [PATCH 1233/1350] drivers: drm: rp1-dsi: Implement more DSI options
+ and flags
+
+Now implementing:
+- Per-command selection of LP or HS for commands (previously LP)
+- EoTp transmission option (previously EoTp was always disabled)
+- Non-continuous clock option (previously always continuous)
+- Per-command enabling of ACK request (in command mode only)
+
+Make a plausible (and possibly correct) attempt to measure the
+longest LP command that will fit into vertical blanking lines.
+
+DON'T set both "Burst Mode" and "Sync Events" flags together.
+This is redundant in the standard IP; in this RP1 variant it
+would enable Sync Pulses but may break with some video timings.
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c     |   5 +-
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h     |   3 +-
+ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 106 +++++++++++++++++-----
+ 3 files changed, 91 insertions(+), 23 deletions(-)
+
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
+@@ -396,7 +396,10 @@ ssize_t rp1dsi_host_transfer(struct mipi
+               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)
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
+@@ -86,7 +86,8 @@ void rp1dsi_mipicfg_setup(struct rp1_dsi
+ /* 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);
+--- a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
++++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
+@@ -103,6 +103,24 @@
+ /* 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)
+@@ -1252,8 +1270,8 @@ static u32 dphy_configure_pll(struct rp1
+                              vco_freq, actual_vco_freq, m, refclk, n,
+                              hsfreq_table[dsi->hsfreq_index].hsfreqrange);
+       } else {
+-              drm_warn(dsi->drm,
+-                       "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq);
++              drm_err(dsi->drm,
++                      "rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq);
+       }
+       return actual_vco_freq;
+@@ -1321,7 +1339,7 @@ static void rp1dsi_dpiclk_start(struct r
+       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)",
++               "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])));
+@@ -1365,7 +1383,8 @@ static u32 get_colorcode(enum mipi_dsi_p
+ void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
+ {
+-      u32 timeout, mask, vid_mode_cfg;
++      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);
+@@ -1374,19 +1393,31 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+       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;
+-      else if (8 * dsi->lanes > bpp)
+-              vid_mode_cfg &= ~0x400; /* PULSE && inexact DPICLK => fix HBP time */
++      /*
++       * 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);
+@@ -1397,9 +1428,9 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+               timeout = 0;
+       DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL);
+       DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL);
++      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(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX));
++                (RP1DSI_TO_CLK_DIV << 8) | clkdiv);
+       /* Configure video timings */
+       DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
+@@ -1425,6 +1456,18 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+                 (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);
+@@ -1434,9 +1477,9 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+       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 */
+@@ -1460,7 +1503,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *ds
+                       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;
+@@ -1471,6 +1515,24 @@ void rp1dsi_dsi_send(struct rp1_dsi *dsi
+               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++;
+@@ -1504,8 +1566,10 @@ int rp1dsi_dsi_recv(struct rp1_dsi *dsi,
+                       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 */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch b/target/linux/bcm27xx/patches-6.6/950-1234-rtc-pcf8523-Fix-oscillator-stop-bit-handling-reading.patch
new file mode 100644 (file)
index 0000000..8b63411
--- /dev/null
@@ -0,0 +1,53 @@
+From 8beb6891489c3c99618a7390578109aadfdf8901 Mon Sep 17 00:00:00 2001
+From: Axel <48924884+Paladinking@users.noreply.github.com>
+Date: Wed, 28 Aug 2024 09:46:13 +0200
+Subject: [PATCH 1234/1350] rtc: pcf8523: Fix oscillator stop bit handling
+ reading from Control_1
+
+The check if the oscillator stop bit is set was reading from Control_1
+register instead of the Seconds register.
+This caused the Seconds register to be incorrectly changed if bit 7 of
+Control_1 happens to be set.
+
+Signed-off-by: Axel Hammarberg <axel.hammarberg@gmail.com>
+---
+ drivers/rtc/rtc-pcf8523.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/rtc/rtc-pcf8523.c
++++ b/drivers/rtc/rtc-pcf8523.c
+@@ -108,10 +108,10 @@ static int pcf8523_rtc_read_time(struct
+       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
+@@ -120,10 +120,10 @@ static int pcf8523_rtc_read_time(struct
+                * 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;
+@@ -135,7 +135,7 @@ static int pcf8523_rtc_read_time(struct
+               if (value & PCF8523_SECONDS_OS)
+                       return -EAGAIN;
+-              regs[0] = value;
++              regs[PCF8523_REG_SECONDS] = value;
+       }
+       tm->tm_sec = bcd2bin(regs[3] & 0x7f);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch b/target/linux/bcm27xx/patches-6.6/950-1235-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch
new file mode 100644 (file)
index 0000000..5f8cf8d
--- /dev/null
@@ -0,0 +1,3352 @@
+From a44f17d8193b69aedb1beebf5ad885a88b1c6615 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Fri, 2 Aug 2024 11:01:24 +0100
+Subject: [PATCH 1235/1350] drivers: media: pci: Update Hailo accelerator
+ device driver to v4.18.0
+
+Sourced from https://github.com/hailo-ai/hailort-drivers/
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/pci/hailo/Makefile              |   2 +
+ drivers/media/pci/hailo/common/fw_operation.c |   2 +-
+ drivers/media/pci/hailo/common/fw_operation.h |   2 +-
+ .../media/pci/hailo/common/fw_validation.c    |  10 +-
+ .../media/pci/hailo/common/fw_validation.h    |   5 +-
+ .../pci/hailo/common/hailo_ioctl_common.h     | 240 +++++++----
+ .../media/pci/hailo/common/hailo_resource.c   |   2 +-
+ .../media/pci/hailo/common/hailo_resource.h   |   2 +-
+ drivers/media/pci/hailo/common/pcie_common.c  | 367 +++++++++++++----
+ drivers/media/pci/hailo/common/pcie_common.h  |  42 +-
+ drivers/media/pci/hailo/common/utils.h        |  24 +-
+ drivers/media/pci/hailo/common/vdma_common.c  | 371 +++++++++++++-----
+ drivers/media/pci/hailo/common/vdma_common.h  |  34 +-
+ drivers/media/pci/hailo/src/fops.c            | 104 +++--
+ drivers/media/pci/hailo/src/fops.h            |   1 +
+ 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            |  93 ++++-
+ drivers/media/pci/hailo/src/pcie.h            |   2 +
+ drivers/media/pci/hailo/src/sysfs.c           |   9 +
+ drivers/media/pci/hailo/src/utils.c           |   1 -
+ .../pci/hailo/utils/integrated_nnc_utils.c    | 101 +++++
+ .../pci/hailo/utils/integrated_nnc_utils.h    |  30 ++
+ drivers/media/pci/hailo/vdma/ioctl.c          |  53 ++-
+ drivers/media/pci/hailo/vdma/ioctl.h          |   6 +-
+ drivers/media/pci/hailo/vdma/memory.c         | 148 ++++++-
+ drivers/media/pci/hailo/vdma/memory.h         |   4 +-
+ drivers/media/pci/hailo/vdma/vdma.c           |  80 ++--
+ drivers/media/pci/hailo/vdma/vdma.h           |  30 +-
+ 29 files changed, 1536 insertions(+), 403 deletions(-)
+ 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 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.c
+ create mode 100755 drivers/media/pci/hailo/utils/integrated_nnc_utils.h
+
+--- a/drivers/media/pci/hailo/Makefile
++++ b/drivers/media/pci/hailo/Makefile
+@@ -10,6 +10,7 @@ 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
+@@ -18,6 +19,7 @@ hailo_pci-objs += $(COMMON_SRC_DIRECTORY
+ 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
+--- a/drivers/media/pci/hailo/common/fw_operation.c
++++ b/drivers/media/pci/hailo/common/fw_operation.c
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ **/
+--- a/drivers/media/pci/hailo/common/fw_operation.h
++++ b/drivers/media/pci/hailo/common/fw_operation.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved.
+ **/
+--- a/drivers/media/pci/hailo/common/fw_validation.c
++++ b/drivers/media/pci/hailo/common/fw_validation.c
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -28,16 +28,18 @@ int FW_VALIDATION__validate_fw_header(ui
+     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; 
++        expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO8;
+         break;
++    case HAILO_BOARD_TYPE_HAILO10H_LEGACY:
+     case HAILO_BOARD_TYPE_HAILO15:
+-        expected_firmware_magic = FIRMWARE_HEADER_MAGIC_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;
+--- a/drivers/media/pci/hailo/common/fw_validation.h
++++ b/drivers/media/pci/hailo/common/fw_validation.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -11,8 +11,7 @@
+ #define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0)
+ #define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB)
+-// TODO - HRT-11344 : change fw magic to pluto specific
+-#define FIRMWARE_HEADER_MAGIC_PLUTO (0xE905DAAB)
++#define FIRMWARE_HEADER_MAGIC_PLUTO (0xF94739AB)
+ #ifndef HAILO_EMULATOR
+ #define FIRMWARE_WAIT_TIMEOUT_MS (5000)
+--- a/drivers/media/pci/hailo/common/hailo_ioctl_common.h
++++ b/drivers/media/pci/hailo/common/hailo_ioctl_common.h
+@@ -6,6 +6,14 @@
+ #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
+@@ -23,14 +31,17 @@
+ #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_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)
+-#define INVALID_VDMA_CHANNEL (0xff)
+ #if !defined(__cplusplus) && defined(NTDDI_VERSION)
+ #include <wdm.h>
+@@ -53,14 +64,23 @@ typedef uint8_t bool;
+ #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,
++DEFINE_GUID (GUID_DEVINTERFACE_HailoKM_NNC,
+     0xd88d31f1,0xfede,0x4e71,0xac,0x2a,0x6c,0xe0,0x01,0x8c,0x15,0x01);
+-#define HAILO_GENERAL_IOCTL_MAGIC 0
+-#define HAILO_VDMA_IOCTL_MAGIC    1
+-#define HAILO_NON_LINUX_IOCTL_MAGIC 2
++// {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)
+@@ -114,9 +134,11 @@ static ULONG FORCEINLINE _IOC_(ULONG nr,
+ #define _IOWR_      _IOWR
+ #define _IO_        _IO
+-#define HAILO_GENERAL_IOCTL_MAGIC 'g'
+-#define HAILO_VDMA_IOCTL_MAGIC 'v'
+-#define HAILO_NON_LINUX_IOCTL_MAGIC 'w'
++#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 <devctl.h>
+@@ -132,7 +154,6 @@ static ULONG FORCEINLINE _IOC_(ULONG nr,
+ #define _IO_    __DION
+ #define HAILO_GENERAL_IOCTL_MAGIC   _DCMD_ALL
+ #define HAILO_VDMA_IOCTL_MAGIC      _DCMD_MISC
+-#define HAILO_NON_LINUX_IOCTL_MAGIC _DCMD_PROC
+ #else // #ifdef _MSC_VER
+ #error "unsupported platform!"
+@@ -161,6 +182,16 @@ enum hailo_dma_data_direction {
+     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,
+@@ -170,10 +201,19 @@ enum hailo_allocation_mode {
+     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)
+-    void* user_address;                             // in
++    uintptr_t user_address;                         // in
+ #elif defined(__QNX__)
+     shm_handle_t shared_memory_handle;              // in
+ #else
+@@ -181,6 +221,7 @@ struct hailo_vdma_buffer_map_params {
+ #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
+ };
+@@ -204,31 +245,27 @@ struct hailo_desc_list_release_params {
+     uintptr_t desc_handle;      // in
+ };
+-/* structure used in ioctl HAILO_NON_LINUX_DESC_LIST_MMAP */
+-struct hailo_non_linux_desc_list_mmap_params {
+-    uintptr_t desc_handle;  // in
+-    size_t size;            // in
+-    void* user_address;     // out
+-};
+-
+ /* structure used in ioctl HAILO_DESC_LIST_BIND_VDMA_BUFFER */
+-struct hailo_desc_list_bind_vdma_buffer_params {
++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_INTERRUPTS_ENABLE */
+-struct hailo_vdma_interrupts_enable_params {
++/* 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_INTERRUPTS_DISABLE */
+-struct hailo_vdma_interrupts_disable_params {
++/* structure used in ioctl HAILO_VDMA_DISABLE_CHANNELS */
++struct hailo_vdma_disable_channels_params {
+     uint32_t channels_bitmap_per_engine[MAX_VDMA_ENGINES];  // in
+ };
+@@ -237,7 +274,7 @@ struct hailo_vdma_interrupts_channel_dat
+     uint8_t engine_index;
+     uint8_t channel_index;
+     bool is_active;                 // If not activate, num_processed is ignored.
+-    uint16_t host_num_processed;
++    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
+@@ -312,6 +349,10 @@ enum hailo_transfer_memory_type {
+     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,
+ };
+@@ -352,15 +393,26 @@ 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,
+@@ -428,15 +480,6 @@ struct hailo_vdma_transfer_buffer {
+     uint32_t size;                     // in
+ };
+-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,
+-};
+-
+ // 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)
+@@ -460,6 +503,35 @@ struct hailo_vdma_launch_transfer_params
+                                                                         // 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
+@@ -469,8 +541,8 @@ struct tCompatibleHailoIoctlData
+     ULONG_PTR Value;
+     union {
+         struct hailo_memory_transfer_params MemoryTransfer;
+-        struct hailo_vdma_interrupts_enable_params VdmaInterruptsEnable;
+-        struct hailo_vdma_interrupts_disable_params VdmaInterruptsDisable;
++        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;
+@@ -479,14 +551,17 @@ struct tCompatibleHailoIoctlData
+         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_bind_vdma_buffer_params DescListBind;
++        struct hailo_desc_list_program_params DescListProgram;
+         struct hailo_d2h_notification D2HNotification;
+         struct hailo_device_properties DeviceProperties;
+         struct hailo_driver_info DriverInfo;
+-        struct hailo_non_linux_desc_list_mmap_params DescListMmap;
+         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
+@@ -495,30 +570,20 @@ struct tCompatibleHailoIoctlData
+ enum hailo_general_ioctl_code {
+     HAILO_MEMORY_TRANSFER_CODE,
+-    HAILO_FW_CONTROL_CODE,
+-    HAILO_READ_NOTIFICATION_CODE,
+-    HAILO_DISABLE_NOTIFICATION_CODE,
+     HAILO_QUERY_DEVICE_PROPERTIES_CODE,
+     HAILO_QUERY_DRIVER_INFO_CODE,
+-    HAILO_READ_LOG_CODE,
+-    HAILO_RESET_NN_CORE_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_FW_CONTROL                _IOWR_(HAILO_GENERAL_IOCTL_MAGIC,  HAILO_FW_CONTROL_CODE,                 struct hailo_fw_control)
+-#define HAILO_READ_NOTIFICATION         _IOW_(HAILO_GENERAL_IOCTL_MAGIC,   HAILO_READ_NOTIFICATION_CODE,          struct hailo_d2h_notification)
+-#define HAILO_DISABLE_NOTIFICATION      _IO_(HAILO_GENERAL_IOCTL_MAGIC,    HAILO_DISABLE_NOTIFICATION_CODE)
+ #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)
+-#define HAILO_READ_LOG                  _IOWR_(HAILO_GENERAL_IOCTL_MAGIC,  HAILO_READ_LOG_CODE,                   struct hailo_read_log_params)
+-#define HAILO_RESET_NN_CORE             _IO_(HAILO_GENERAL_IOCTL_MAGIC,    HAILO_RESET_NN_CORE_CODE)
+ enum hailo_vdma_ioctl_code {
+-    HAILO_VDMA_INTERRUPTS_ENABLE_CODE,
+-    HAILO_VDMA_INTERRUPTS_DISABLE_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,
+@@ -526,7 +591,7 @@ enum hailo_vdma_ioctl_code {
+     HAILO_VDMA_BUFFER_SYNC_CODE,
+     HAILO_DESC_LIST_CREATE_CODE,
+     HAILO_DESC_LIST_RELEASE_CODE,
+-    HAILO_DESC_LIST_BIND_VDMA_BUFFER_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,
+@@ -538,38 +603,67 @@ enum hailo_vdma_ioctl_code {
+     HAILO_VDMA_IOCTL_MAX_NR,
+ };
+-#define HAILO_VDMA_INTERRUPTS_ENABLE          _IOR_(HAILO_VDMA_IOCTL_MAGIC,  HAILO_VDMA_INTERRUPTS_ENABLE_CODE,            struct hailo_vdma_interrupts_enable_params)
+-#define HAILO_VDMA_INTERRUPTS_DISABLE         _IOR_(HAILO_VDMA_IOCTL_MAGIC,  HAILO_VDMA_INTERRUPTS_DISABLE_CODE,           struct hailo_vdma_interrupts_disable_params)
++#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_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_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_BIND_VDMA_BUFFER      _IOR_(HAILO_VDMA_IOCTL_MAGIC,  HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE,         struct hailo_desc_list_bind_vdma_buffer_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_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_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_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)
+-#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
++};
+-enum hailo_non_linux_ioctl_code {
+-    HAILO_NON_LINUX_DESC_LIST_MMAP_CODE,
++#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_NON_LINUX_IOCTL_MAX_NR,
++    HAILO_SOC_IOCTL_MAX_NR,
+ };
+-#define HAILO_NON_LINUX_DESC_LIST_MMAP _IOWR_(HAILO_NON_LINUX_IOCTL_MAGIC, HAILO_NON_LINUX_DESC_LIST_MMAP_CODE, struct hailo_non_linux_desc_list_mmap_params)
++#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_ */
+--- a/drivers/media/pci/hailo/common/hailo_resource.c
++++ b/drivers/media/pci/hailo/common/hailo_resource.c
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+--- a/drivers/media/pci/hailo/common/hailo_resource.h
++++ b/drivers/media/pci/hailo/common/hailo_resource.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+--- a/drivers/media/pci/hailo/common/pcie_common.c
++++ b/drivers/media/pci/hailo/common/pcie_common.c
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -10,6 +10,8 @@
+ #include <linux/bug.h>
+ #include <linux/delay.h>
+ #include <linux/kernel.h>
++#include <linux/printk.h>
++#include <linux/device.h>
+ #define BSC_IMASK_HOST (0x0188)
+@@ -19,14 +21,13 @@
+ #define PO2_ROUND_UP(size, alignment) ((size + alignment-1) & ~(alignment-1))
+-#define ATR0_PARAM (0x17)
+-#define ATR0_SRC_ADDR (0x0)
+-#define ATR0_TRSL_ADDR2 (0x0)
+-#define ATR0_TRSL_PARAM (6)
++#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 ATR0_TABLE_SIZE (0x1000u)
+-#define ATR0_TABLE_SIZE_MASK (0x1000u - 1)
+ #define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000)
+ #define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x20000)
+@@ -45,8 +46,13 @@
+ #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)
+-typedef u32 hailo_ptr_t;
++#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;
+@@ -58,14 +64,11 @@ struct hailo_fw_addresses {
+     u32 core_fw_header;
+     u32 atr0_trsl_addr1;
+     u32 raise_ready_offset;
++    u32 boot_status;
+ };
+-struct hailo_atr_config {
+-    u32 atr_param;
+-    u32 atr_src;
+-    u32 atr_trsl_addr_1;
+-    u32 atr_trsl_addr_2;
+-    u32 atr_trsl_param;
++struct loading_stage {
++    const struct hailo_file_batch *batch;
+ };
+ struct hailo_board_compatibility {
+@@ -73,6 +76,69 @@ struct hailo_board_compatibility {
+     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] = {
+@@ -87,6 +153,7 @@ static const struct hailo_board_compatib
+             .core_fw_header = 0xA0000,
+             .atr0_trsl_addr1 = 0x60000000,
+             .raise_ready_offset = 0x1684,
++            .boot_status = 0xe0000,
+         },
+         .fw_filename = "hailo/hailo8_fw.bin",
+         .board_cfg = {
+@@ -100,7 +167,7 @@ static const struct hailo_board_compatib
+             .max_size = PCIE_HAILO8_FW_CFG_MAX_SIZE,
+         },
+     },
+-    [HAILO_BOARD_TYPE_HAILO15] = {
++    [HAILO_BOARD_TYPE_HAILO10H_LEGACY] = {
+         .fw_addresses = {
+             .boot_fw_header = 0x88000,
+             .boot_fw_trigger = 0x88c98,
+@@ -111,6 +178,7 @@ static const struct hailo_board_compatib
+             .core_fw_header = 0xC0000,
+             .atr0_trsl_addr1 = 0x000BE000,
+             .raise_ready_offset = 0x1754,
++            .boot_status = 0x80000,
+         },
+         .fw_filename = "hailo/hailo15_fw.bin",
+         .board_cfg = {
+@@ -124,6 +192,39 @@ static const struct hailo_board_compatib
+             .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] = {
+@@ -138,6 +239,7 @@ static const struct hailo_board_compatib
+             .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 = {
+@@ -225,7 +327,7 @@ int hailo_pcie_read_firmware_control(str
+     // 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;
+ }
+@@ -253,93 +355,111 @@ int hailo_pcie_read_firmware_notificatio
+     return hailo_read_firmware_notification(&notification_resource, notification);
+ }
+-static void write_atr_table(struct hailo_pcie_resources *resources,
+-    struct hailo_atr_config *atr)
++int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index)
+ {
+-    hailo_resource_write_buffer(&resources->config, ATR0_PCIE_BRIDGE_OFFSET,
+-        sizeof(*atr), (void*)atr);
+-}
++    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
++    };
+-static void read_atr_table(struct hailo_pcie_resources *resources,
+-    struct hailo_atr_config *atr)
+-{
+-    hailo_resource_read_buffer(&resources->config, ATR0_PCIE_BRIDGE_OFFSET,
+-        sizeof(*atr), (void*)atr);
++    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);
+ }
+-static void configure_atr_table(struct hailo_pcie_resources *resources,
+-    hailo_ptr_t base_address)
++void hailo_pcie_read_atr_table(struct hailo_resource *bridge_config, struct hailo_atr_config *atr, u32 atr_index)
+ {
+-    struct hailo_atr_config atr = {
+-        .atr_param = ATR0_PARAM,
+-        .atr_src = ATR0_SRC_ADDR,
+-        .atr_trsl_addr_1 = (u32)base_address,
+-        .atr_trsl_addr_2 = ATR0_TRSL_ADDR2,
+-        .atr_trsl_param = ATR0_TRSL_PARAM
+-    };
+-    write_atr_table(resources, &atr);
++    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);
+-    configure_atr_table(resources, dest);
++    (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);
+-    configure_atr_table(resources, src);
++    (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.
+-static void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len)
++void write_memory(struct hailo_pcie_resources *resources, hailo_ptr_t dest, const void *src, u32 len)
+ {
+-    hailo_ptr_t base_address = dest & ~ATR0_TABLE_SIZE_MASK;
++    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 + ATR0_TABLE_SIZE - dest, len);
++        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, ATR0_TABLE_SIZE);
++        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)
+ {
+-    hailo_ptr_t base_address = src & ~ATR0_TABLE_SIZE_MASK;
++    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 + ATR0_TABLE_SIZE - src, len);
++        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, ATR0_TABLE_SIZE);
++        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,
+@@ -367,7 +487,7 @@ static void hailo_write_core_firmware(st
+     write_memory(resources, fw_addresses->core_fw_header, fw_header, sizeof(firmware_header_t));
+ }
+-static void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources)
++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;
+@@ -376,6 +496,17 @@ static void hailo_trigger_firmware_boot(
+         (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.
+@@ -408,11 +539,14 @@ static int FW_VALIDATION__validate_fw_he
+         goto exit;
+     }
+-    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;
++    // 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) {
+@@ -437,6 +571,70 @@ 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;
+@@ -457,10 +655,25 @@ int hailo_pcie_write_firmware(struct hai
+     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 = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1);
+-    u32 atr_value = hailo_resource_read32(&resources->config, offset);
++    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;
+ }
+@@ -516,7 +729,7 @@ void hailo_pcie_update_channel_interrupt
+     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 < VDMA_DEST_CHANNELS_START) ? 0 : 8;
++            u32 offset = (i & 16) ? 8 : 0;
+             hailo_set_bit((((int)i*8) / MAX_VDMA_CHANNELS_PER_ENGINE) + offset, &mask);
+         }
+     }
+@@ -531,7 +744,8 @@ void hailo_pcie_enable_interrupts(struct
+     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;
++    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);
+ }
+@@ -569,16 +783,10 @@ long hailo_pcie_read_firmware_log(struct
+ static int direct_memory_transfer(struct hailo_pcie_resources *resources,
+     struct hailo_memory_transfer_params *params)
+ {
+-    int err = -EINVAL;
+-    struct hailo_atr_config previous_atr = {0};
+-
+     if (params->address > U32_MAX) {
+         return -EFAULT;
+     }
+-    // Store previous ATR (Read/write modify the ATR).
+-    read_atr_table(resources, &previous_atr);
+-
+     switch (params->transfer_direction) {
+     case TRANSFER_READ:
+         read_memory(resources, (u32)params->address, params->buffer, (u32)params->count);
+@@ -587,14 +795,10 @@ static int direct_memory_transfer(struct
+         write_memory(resources, (u32)params->address, params->buffer, (u32)params->count);
+         break;
+     default:
+-        err = -EINVAL;
+-        goto restore_atr;
++        return -EINVAL;
+     }
+-    err = 0;
+-restore_atr:
+-    write_atr_table(resources, &previous_atr);
+-    return err;
++    return 0;
+ }
+ int hailo_pcie_memory_transfer(struct hailo_pcie_resources *resources, struct hailo_memory_transfer_params *params)
+@@ -623,6 +827,24 @@ bool hailo_pcie_is_device_connected(stru
+     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)
+ {
+@@ -637,5 +859,14 @@ struct hailo_vdma_hw hailo_pcie_vdma_hw
+     .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,
++};
+-};
+\ No newline at end of file
++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
+--- a/drivers/media/pci/hailo/common/pcie_common.h
++++ b/drivers/media/pci/hailo/common/pcie_common.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -14,11 +14,13 @@
+ #include "vdma_common.h"
+ #include <linux/types.h>
++#include <linux/firmware.h>
+ #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)
+@@ -40,17 +42,35 @@
+ #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
+ };
+@@ -66,6 +86,14 @@ struct hailo_config_constants {
+     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 {
+@@ -103,6 +131,7 @@ int hailo_pcie_write_firmware_control(st
+ 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);
+@@ -120,6 +149,17 @@ int hailo_pcie_memory_transfer(struct ha
+ 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
+ }
+--- a/drivers/media/pci/hailo/common/utils.h
++++ b/drivers/media/pci/hailo/common/utils.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -11,6 +11,12 @@
+ #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"
+ {
+@@ -28,6 +34,22 @@ static inline void hailo_set_bit(int 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
+--- a/drivers/media/pci/hailo/common/vdma_common.c
++++ b/drivers/media/pci/hailo/common/vdma_common.c
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -17,25 +17,37 @@
+ #define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5)
+-#define CHANNEL_HOST_OFFSET(channel_index) CHANNEL_BASE_OFFSET(channel_index) + \
+-    (channel_index < VDMA_DEST_CHANNELS_START ? 0 : 0x10)
+-#define CHANNEL_DEVICE_OFFSET(channel_index) CHANNEL_BASE_OFFSET(channel_index) + \
+-    (channel_index < VDMA_DEST_CHANNELS_START ? 0x10 : 0)
+ #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)
+@@ -46,10 +58,14 @@
+ #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)
+@@ -146,18 +162,7 @@ void hailo_vdma_program_descriptor(struc
+ static u8 get_channel_id(u8 channel_index)
+ {
+-    if (channel_index < VDMA_DEST_CHANNELS_START) {
+-        // H2D channel
+-        return channel_index;
+-    }
+-    else if ((channel_index >= VDMA_DEST_CHANNELS_START) &&
+-             (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE)) {
+-        // D2H channel
+-        return channel_index - VDMA_DEST_CHANNELS_START;
+-    }
+-    else {
+-        return INVALID_VDMA_CHANNEL;
+-    }
++    return (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE) ? (channel_index & 0xF) : INVALID_VDMA_CHANNEL;
+ }
+ static int program_descriptors_in_chunk(
+@@ -198,12 +203,36 @@ static int program_descriptors_in_chunk(
+     return (int)desc_per_chunk;
+ }
+-int hailo_vdma_program_descriptors_list(
++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)
++    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;
+@@ -260,9 +289,49 @@ int hailo_vdma_program_descriptors_list(
+         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;
+@@ -270,12 +339,12 @@ static bool channel_control_reg_is_activ
+ static int validate_channel_state(struct hailo_vdma_channel *channel)
+ {
+-    const u8 control = ioread8(channel->host_regs + CHANNEL_CONTROL_OFFSET);
+-    const u16 hw_num_avail = ioread16(channel->host_regs + CHANNEL_NUM_AVAIL_OFFSET);
++    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)) {
+-        pr_err("Channel %d is not active\n", channel->index);
+-        return -EBUSY;
++        return -ECONNRESET;
+     }
+     if (hw_num_avail != channel->state.num_avail) {
+@@ -287,51 +356,16 @@ static int validate_channel_state(struct
+     return 0;
+ }
+-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 void set_num_avail(u8 __iomem *host_regs, u16 num_avail)
+ {
+-    iowrite16(num_avail, host_regs + CHANNEL_NUM_AVAIL_OFFSET);
++    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 ioread16(host_regs + CHANNEL_NUM_PROC_OFFSET);
+-}
+-
+-static int program_last_desc(
+-    struct hailo_vdma_descriptors_list *desc_list,
+-    u32 starting_desc,
+-    struct hailo_vdma_mapped_transfer_buffer *transfer_buffer)
+-{
+-    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) + DESCRIPTOR_DESC_CONTROL);
+-    return (int)total_descs;
++    return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET));
+ }
+ int hailo_vdma_launch_transfer(
+@@ -365,6 +399,11 @@ int hailo_vdma_launch_transfer(
+         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);
+@@ -376,25 +415,17 @@ int hailo_vdma_launch_transfer(
+         return -EINVAL;
+     }
+-    if (is_debug) {
+-        ret = validate_channel_state(channel);
+-        if (ret < 0) {
+-            return ret;
+-        }
+-    }
+-
+     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 = should_bind ?
+-            hailo_vdma_program_descriptors_list(vdma_hw, desc_list, starting_desc, &buffers[i], channel->index) :
+-            program_last_desc(desc_list, starting_desc, &buffers[i]);
+-        if (ret < 0) {
+-            return ret;
+-        }
++        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;
+@@ -406,8 +437,6 @@ int hailo_vdma_launch_transfer(
+     desc_list->desc_list[first_desc].PageSize_DescControl |=
+         get_interrupts_bitmask(vdma_hw, first_interrupts_domain, is_debug);
+-    desc_list->desc_list[last_desc].PageSize_DescControl |=
+-        get_interrupts_bitmask(vdma_hw, last_desc_interrupts, is_debug);
+     ongoing_transfer.last_desc = (u16)last_desc;
+     ongoing_transfer.is_debug = is_debug;
+@@ -477,8 +506,21 @@ static void channel_state_init(struct ha
+     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)
++    const struct hailo_resource *channel_registers, u32 src_channels_bitmask)
+ {
+     u8 channel_index = 0;
+     struct hailo_vdma_channel *channel;
+@@ -489,8 +531,8 @@ void hailo_vdma_engine_init(struct hailo
+     for_each_vdma_channel(engine, channel, channel_index) {
+         u8 __iomem *regs_base = (u8 __iomem *)channel_registers->address;
+-        channel->host_regs = regs_base + CHANNEL_HOST_OFFSET(channel_index);
+-        channel->device_regs = regs_base + CHANNEL_DEVICE_OFFSET(channel_index);
++        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;
+@@ -502,7 +544,15 @@ void hailo_vdma_engine_init(struct hailo
+     }
+ }
+-void hailo_vdma_engine_enable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap,
++/**
++ * 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;
+@@ -518,7 +568,14 @@ void hailo_vdma_engine_enable_channel_in
+     engine->enabled_channels |= bitmap;
+ }
+-void hailo_vdma_engine_disable_channel_interrupts(struct hailo_vdma_engine *engine, u32 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;
+@@ -582,11 +639,11 @@ void hailo_vdma_engine_set_channel_inter
+ }
+ static void fill_channel_irq_data(struct hailo_vdma_interrupts_channel_data *irq_data,
+-    struct hailo_vdma_engine *engine, struct hailo_vdma_channel *channel, u16 num_proc,
++    struct hailo_vdma_engine *engine, struct hailo_vdma_channel *channel, u8 transfers_completed,
+     bool validation_success)
+ {
+-    u8 host_control = ioread8(channel->host_regs + CHANNEL_CONTROL_OFFSET);
+-    u8 device_control = ioread8(channel->device_regs + CHANNEL_CONTROL_OFFSET);
++    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;
+@@ -594,9 +651,9 @@ static void fill_channel_irq_data(struct
+     irq_data->is_active = channel_control_reg_is_active(host_control) &&
+         channel_control_reg_is_active(device_control);
+-    irq_data->host_num_processed = num_proc;
+-    irq_data->host_error = ioread8(channel->host_regs + CHANNEL_ERROR_OFFSET);
+-    irq_data->device_error = ioread8(channel->device_regs + CHANNEL_ERROR_OFFSET);
++    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;
+ }
+@@ -635,7 +692,12 @@ int hailo_vdma_engine_fill_irq_data(stru
+     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;
+         }
+@@ -673,12 +735,143 @@ int hailo_vdma_engine_fill_irq_data(stru
+             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, hw_num_proc, validation_success);
++            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
+--- a/drivers/media/pci/hailo/common/vdma_common.h
++++ b/drivers/media/pci/hailo/common/vdma_common.h
+@@ -1,4 +1,4 @@
+-// SPDX-License-Identifier: GPL-2.0
++// SPDX-License-Identifier: MIT
+ /**
+  * Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
+  **/
+@@ -30,8 +30,8 @@ struct hailo_vdma_descriptor {
+ 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;
++    u32                           desc_count;  // Must be power of 2 if is_circular is set.
++    u16                           desc_page_size;
+     bool                          is_circular;
+ };
+@@ -127,6 +127,9 @@ struct hailo_vdma_hw {
+     // 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) \
+@@ -147,7 +150,11 @@ void hailo_vdma_program_descriptor(struc
+  * @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.
+  */
+@@ -156,7 +163,10 @@ int hailo_vdma_program_descriptors_list(
+     struct hailo_vdma_descriptors_list *desc_list,
+     u32 starting_desc,
+     struct hailo_vdma_mapped_transfer_buffer *buffer,
+-    u8 channel_index);
++    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:
+@@ -191,14 +201,12 @@ int hailo_vdma_launch_transfer(
+     bool is_debug);
+ void hailo_vdma_engine_init(struct hailo_vdma_engine *engine, u8 engine_index,
+-    const struct hailo_resource *channel_registers);
++    const struct hailo_resource *channel_registers, u32 src_channels_bitmask);
+-// enable/disable channels interrupt (does not update interrupts mask because the
+-// implementation is different between PCIe and DRAM DMA. To support it we
+-// can add some ops struct to the engine).
+-void hailo_vdma_engine_enable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap,
++void hailo_vdma_engine_enable_channels(struct hailo_vdma_engine *engine, u32 bitmap,
+     bool measure_timestamp);
+-void hailo_vdma_engine_disable_channel_interrupts(struct hailo_vdma_engine *engine, u32 bitmap);
++
++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,
+@@ -237,6 +245,12 @@ int hailo_vdma_engine_fill_irq_data(stru
+     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
+--- a/drivers/media/pci/hailo/src/fops.c
++++ b/drivers/media/pci/hailo/src/fops.c
+@@ -19,7 +19,6 @@
+ #include <linux/sched/signal.h>
+ #endif
+-#include "hailo_pcie_version.h"
+ #include "utils.h"
+ #include "fops.h"
+ #include "vdma_common.h"
+@@ -27,6 +26,7 @@
+ #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 )
+@@ -210,69 +210,66 @@ l_exit:
+ int hailo_pcie_fops_release(struct inode *inode, struct file *filp)
+ {
+-    struct hailo_pcie_board *pBoard = (struct hailo_pcie_board *)filp->private_data;
++    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 (pBoard) {
+-        hailo_info(pBoard, "(%d: %d-%d): fops_release\n", current->tgid, major, minor);
++    if (board) {
++        hailo_info(board, "(%d: %d-%d): fops_release\n", current->tgid, major, minor);
+-        if (down_interruptible(&pBoard->mutex)) {
+-            hailo_err(pBoard, "fops_release down_interruptible failed");
+-            return -ERESTARTSYS;
+-        }
+-        context = find_file_context(pBoard, filp);
++        down(&board->mutex);
++
++        context = find_file_context(board, filp);
+         if (NULL == context) {
+-            hailo_err(pBoard, "Invalid driver state, file context does not exist\n");
+-            up(&pBoard->mutex);
++            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(pBoard, "Invalid file context\n");
++            hailo_err(board, "Invalid file context\n");
+         }
+-        hailo_pcie_clear_notification_wait_list(pBoard, filp);
++        hailo_pcie_clear_notification_wait_list(board, filp);
+-        if (filp == pBoard->vdma.used_by_filp) {
+-            if (hailo_pcie_driver_down(pBoard)) {
+-                hailo_err(pBoard, "Failed sending FW shutdown event");
++        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, &pBoard->vdma, filp);
++        hailo_vdma_file_context_finalize(&context->vdma_context, &board->vdma, filp);
+         release_file_context(context);
+-        if (atomic_dec_and_test(&pBoard->ref_count)) {
++        if (atomic_dec_and_test(&board->ref_count)) {
+             // Disable interrupts
+-            hailo_disable_interrupts(pBoard);
++            hailo_disable_interrupts(board);
+             if (power_mode_enabled()) {
+-                if (pBoard->pDev && pci_set_power_state(pBoard->pDev, PCI_D3hot) < 0) {
+-                    hailo_err(pBoard, "Failed setting power state to D3hot");
++                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 (!pBoard->pDev) {
+-                hailo_dbg(pBoard, "fops_close, freed board\n");
+-                up(&pBoard->mutex);
+-                kfree(pBoard);
+-                pBoard = NULL;
++            if (!board->pDev) {
++                hailo_dbg(board, "fops_release, freed board\n");
++                up(&board->mutex);
++                kfree(board);
++                board = NULL;
+             } else {
+-
+-                hailo_dbg(pBoard, "fops_close, released resources for board\n");
+-                up(&pBoard->mutex);
++                hailo_dbg(board, "fops_release, released resources for board\n");
++                up(&board->mutex);
+             }
+         } else {
+-            up(&pBoard->mutex);
++            up(&board->mutex);
+         }
+-        hailo_dbg(pBoard, "(%d: %d-%d): fops_close: SUCCESS on /dev/hailo%d\n", current->tgid,
++        hailo_dbg(board, "(%d: %d-%d): fops_release: SUCCESS on /dev/hailo%d\n", current->tgid,
+             major, minor, minor);
+     }
+@@ -394,6 +391,10 @@ irqreturn_t hailo_irqhandler(int irq, vo
+             }
+         }
++        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);
+@@ -602,26 +603,35 @@ static long hailo_query_driver_info(stru
+     return 0;
+ }
+-static long hailo_general_ioctl(struct hailo_file_context *context, struct hailo_pcie_board *board,
+-    unsigned int cmd, unsigned long arg, struct file *filp, bool *should_up_board_mutex)
++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_QUERY_DEVICE_PROPERTIES:
+-        return hailo_query_device_properties(board, arg);
+-    case HAILO_QUERY_DRIVER_INFO:
+-        return hailo_query_driver_info(board, arg);
+     case HAILO_READ_LOG:
+         return hailo_read_log_ioctl(board, arg);
+     default:
+-        hailo_err(board, "Invalid general ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd));
++        hailo_err(board, "Invalid nnc ioctl code 0x%x (nr: %d)\n", cmd, _IOC_NR(cmd));
+         return -ENOTTY;
+     }
+ }
+@@ -673,12 +683,28 @@ long hailo_pcie_fops_unlockedioctl(struc
+     switch (_IOC_TYPE(cmd)) {
+     case HAILO_GENERAL_IOCTL_MAGIC:
+-        err = hailo_general_ioctl(context, board, cmd, arg, filp, &should_up_board_mutex);
++        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;
+--- a/drivers/media/pci/hailo/src/fops.h
++++ b/drivers/media/pci/hailo/src/fops.h
+@@ -11,6 +11,7 @@ int hailo_pcie_fops_release(struct inode
+ 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);
+--- /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(&params, (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, &params, 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(&params, (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
+--- /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
+--- a/drivers/media/pci/hailo/src/pcie.c
++++ b/drivers/media/pci/hailo/src/pcie.c
+@@ -20,7 +20,6 @@
+ #define KERNEL_CODE   1
+-#include "hailo_pcie_version.h"
+ #include "hailo_ioctl_common.h"
+ #include "pcie.h"
+ #include "fops.h"
+@@ -45,6 +44,7 @@ enum hailo_allocate_driver_buffer_driver
+ 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;
+@@ -322,7 +322,7 @@ static int hailo_write_config(struct hai
+ static bool wait_for_firmware_completion(struct completion *fw_load_completion)
+ {
+-    return (0 != wait_for_completion_timeout(fw_load_completion, FIRMWARE_WAIT_TIMEOUT_MS));
++    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,
+@@ -330,6 +330,7 @@ static int hailo_load_firmware(struct ha
+ {
+     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");
+@@ -368,7 +369,8 @@ static int hailo_load_firmware(struct ha
+     release_firmware(firmware);
+     if (!wait_for_firmware_completion(fw_load_completion)) {
+-        hailo_dev_err(dev, "Timeout waiting for firmware..\n");
++        boot_status = hailo_get_boot_status(resources);
++        hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status);
+         return -ETIMEDOUT;
+     }
+@@ -376,6 +378,55 @@ static int hailo_load_firmware(struct ha
+     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;
+@@ -388,8 +439,21 @@ static int hailo_activate_board(struct h
+         return err;
+     }
+-    err = hailo_load_firmware(&board->pcie_resources, &board->pDev->dev,
+-        &board->fw_loaded_completion);
++    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);
+@@ -513,8 +577,23 @@ static int pcie_resources_init(struct pc
+         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;
+@@ -676,6 +755,7 @@ static int hailo_pcie_probe(struct pci_d
+     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);
+@@ -1005,6 +1085,9 @@ MODULE_PARM_DESC(force_allocation_from_d
+ 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");
+--- a/drivers/media/pci/hailo/src/pcie.h
++++ b/drivers/media/pci/hailo/src/pcie.h
+@@ -70,6 +70,8 @@ struct hailo_pcie_board {
+     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);
+--- a/drivers/media/pci/hailo/src/sysfs.c
++++ b/drivers/media/pci/hailo/src/sysfs.c
+@@ -26,9 +26,18 @@ static ssize_t device_id_show(struct dev
+ }
+ 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
+ };
+--- a/drivers/media/pci/hailo/src/utils.c
++++ b/drivers/media/pci/hailo/src/utils.c
+@@ -8,7 +8,6 @@
+ #include <linux/module.h>
+ #include <linux/pci.h>
+-#include "hailo_pcie_version.h"
+ #include "pcie.h"
+ #include "utils.h"
+ #include "utils/logs.h"
+--- /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 <linux/uaccess.h>
++#include <asm/io.h>
++#include <linux/of_address.h>
++#include <linux/cdev.h>
++
++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
+--- /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 <linux/platform_device.h>
++#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_ */
+--- a/drivers/media/pci/hailo/vdma/ioctl.c
++++ b/drivers/media/pci/hailo/vdma/ioctl.c
+@@ -12,9 +12,9 @@
+ #include <linux/uaccess.h>
+-long hailo_vdma_interrupts_enable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg)
++long hailo_vdma_enable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg)
+ {
+-    struct hailo_vdma_interrupts_enable_params input;
++    struct hailo_vdma_enable_channels_params input;
+     struct hailo_vdma_engine *engine = NULL;
+     u8 engine_index = 0;
+     u32 channels_bitmap = 0;
+@@ -35,7 +35,7 @@ long hailo_vdma_interrupts_enable_ioctl(
+     for_each_vdma_engine(controller, engine, engine_index) {
+         channels_bitmap = input.channels_bitmap_per_engine[engine_index];
+-        hailo_vdma_engine_enable_channel_interrupts(engine, channels_bitmap,
++        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",
+@@ -45,12 +45,13 @@ long hailo_vdma_interrupts_enable_ioctl(
+     return 0;
+ }
+-long hailo_vdma_interrupts_disable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg)
++long hailo_vdma_disable_channels_ioctl(struct hailo_vdma_controller *controller, unsigned long arg)
+ {
+-    struct hailo_vdma_interrupts_disable_params input;
++    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");
+@@ -61,15 +62,21 @@ long hailo_vdma_interrupts_disable_ioctl
+     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_err(controller->dev, "Trying to disable channels that were not enabled\n");
+-            return -EINVAL;
++            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_interrupts_disable(controller, engine, engine_index,
+-            channels_bitmap);
++        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
+@@ -197,7 +204,7 @@ long hailo_vdma_buffer_map_ioctl(struct
+         return -EFAULT;
+     }
+-    hailo_dev_info(controller->dev, "address %px tgid %d size: %zu\n",
++    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);
+@@ -209,10 +216,9 @@ long hailo_vdma_buffer_map_ioctl(struct
+     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, low_memory_buffer);
++        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 %px\n",
+-            buf_info.user_address);
++        hailo_dev_err(controller->dev, "failed map buffer %lx\n", buf_info.user_address);
+         return PTR_ERR(mapped_buffer);
+     }
+@@ -225,7 +231,7 @@ long hailo_vdma_buffer_map_ioctl(struct
+     }
+     list_add(&mapped_buffer->mapped_user_buffer_list, &context->mapped_user_buffer_list);
+-    hailo_dev_info(controller->dev, "buffer %px (handle %zu) is mapped\n",
++    hailo_dev_info(controller->dev, "buffer %lx (handle %zu) is mapped\n",
+         buf_info.user_address, buf_info.mapped_handle);
+     return 0;
+ }
+@@ -374,10 +380,10 @@ long hailo_desc_list_release_ioctl(struc
+     return 0;
+ }
+-long hailo_desc_list_bind_vdma_buffer(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller,
++long hailo_desc_list_program_ioctl(struct hailo_vdma_file_context *context, struct hailo_vdma_controller *controller,
+     unsigned long arg)
+ {
+-    struct hailo_desc_list_bind_vdma_buffer_params configure_info;
++    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};
+@@ -410,7 +416,10 @@ long hailo_desc_list_bind_vdma_buffer(st
+         &descriptors_buffer->desc_list,
+         configure_info.starting_desc,
+         &transfer_buffer,
+-        configure_info.channel_index
++        configure_info.should_bind,
++        configure_info.channel_index,
++        configure_info.last_interrupts_domain,
++        configure_info.is_debug
+     );
+ }
+@@ -683,11 +692,19 @@ long hailo_vdma_launch_transfer_ioctl(st
+         params.is_debug
+     );
+     if (ret < 0) {
+-        hailo_dev_err(controller->dev, "Failed launch transfer %d\n", ret);
++        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, &params, 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, &params, sizeof(params))) {
+         hailo_dev_err(controller->dev, "copy_to_user fail\n");
+--- a/drivers/media/pci/hailo/vdma/ioctl.h
++++ b/drivers/media/pci/hailo/vdma/ioctl.h
+@@ -8,8 +8,8 @@
+ #include "vdma/vdma.h"
+-long hailo_vdma_interrupts_enable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg);
+-long hailo_vdma_interrupts_disable_ioctl(struct hailo_vdma_controller *controller, unsigned long arg);
++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);
+@@ -19,7 +19,7 @@ long hailo_vdma_buffer_sync_ioctl(struct
+ 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_bind_vdma_buffer(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);
+--- a/drivers/media/pci/hailo/vdma/memory.c
++++ b/drivers/media/pci/hailo/vdma/memory.c
+@@ -11,27 +11,107 @@
+ #include <linux/slab.h>
+ #include <linux/scatterlist.h>
+ #include <linux/sched.h>
++#include <linux/module.h>
+ #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(void __user* user_address, u32 size, struct vm_area_struct *vma,
++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, void __user* user_address, u32 size,
++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,
+-    void __user *user_address, size_t size, enum dma_data_direction direction,
+-    struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer)
++    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) {
+@@ -40,17 +120,19 @@ struct hailo_vdma_buffer *hailo_vdma_buf
+         goto cleanup;
+     }
+-    if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING)) {
+-        vma = find_vma(current->mm, (uintptr_t)user_address);
++    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", (uintptr_t)user_address, size);
++            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))) {
++            (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
+@@ -66,6 +148,14 @@ struct hailo_vdma_buffer *hailo_vdma_buf
+         }
+         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);
+@@ -88,6 +178,7 @@ struct hailo_vdma_buffer *hailo_vdma_buf
+     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;
+@@ -103,11 +194,16 @@ static void unmap_buffer(struct kref *kr
+ {
+     struct hailo_vdma_buffer *buf = container_of(kref, struct hailo_vdma_buffer, kref);
+-    if (!buf->is_mmio) {
+-        dma_unmap_sg(buf->device, buf->sg_table.sgl, buf->sg_table.orig_nents, buf->data_direction);
+-    }
++    // 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);
++        clear_sg_table(&buf->sg_table);
++    }
+     kfree(buf);
+ }
+@@ -164,8 +260,9 @@ void hailo_vdma_buffer_sync(struct hailo
+     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) {
+-        // MMIO buffers don't need to be sync'd
++    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;
+     }
+@@ -404,7 +501,8 @@ void hailo_vdma_clear_continuous_buffer_
+ // 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
+-static int map_mmio_address(void __user* user_address, u32 size, struct vm_area_struct *vma,
++#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;
+@@ -413,7 +511,7 @@ static int map_mmio_address(void __user*
+     unsigned long next_pfn = 0;
+     phys_addr_t phys_addr = 0;
+     dma_addr_t mmio_dma_address = 0;
+-    const uintptr_t virt_addr = (uintptr_t)user_address;
++    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);
+@@ -462,8 +560,21 @@ static int map_mmio_address(void __user*
+     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, void __user *user_address, u32 size,
++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;
+@@ -482,8 +593,7 @@ static int prepare_sg_table(struct sg_ta
+     // 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((unsigned long)user_address,
+-            npages, FOLL_WRITE | FOLL_FORCE, pages);
++        pinned_pages = get_user_pages_compact(user_address, npages, FOLL_WRITE | FOLL_FORCE, pages);
+         mmap_read_unlock(current->mm);
+         if (pinned_pages < 0) {
+--- a/drivers/media/pci/hailo/vdma/memory.h
++++ b/drivers/media/pci/hailo/vdma/memory.h
+@@ -11,8 +11,8 @@
+ #include "vdma/vdma.h"
+-struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev,
+-    void __user *user_address, size_t size, enum dma_data_direction direction,
++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);
+--- a/drivers/media/pci/hailo/vdma/vdma.c
++++ b/drivers/media/pci/hailo/vdma/vdma.c
+@@ -21,7 +21,7 @@
+ static struct hailo_vdma_engine* init_vdma_engines(struct device *dev,
+-    struct hailo_resource *channel_registers_per_engine, size_t engines_count)
++    struct hailo_resource *channel_registers_per_engine, size_t engines_count, u32 src_channels_bitmask)
+ {
+     struct hailo_vdma_engine *engines = NULL;
+     u8 i = 0;
+@@ -33,7 +33,7 @@ static struct hailo_vdma_engine* init_vd
+     }
+     for (i = 0; i < engines_count; i++) {
+-        hailo_vdma_engine_init(&engines[i], i, &channel_registers_per_engine[i]);
++        hailo_vdma_engine_init(&engines[i], i, &channel_registers_per_engine[i], src_channels_bitmask);
+     }
+     return engines;
+@@ -72,7 +72,8 @@ int hailo_vdma_controller_init(struct ha
+     controller->dev = dev;
+     controller->vdma_engines_count = engines_count;
+-    controller->vdma_engines = init_vdma_engines(dev, channel_registers_per_engine, 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);
+@@ -113,36 +114,27 @@ void hailo_vdma_update_interrupts_mask(s
+     controller->ops->update_channel_interrupts(controller, engine_index, engine->enabled_channels);
+ }
+-void hailo_vdma_engine_interrupts_disable(struct hailo_vdma_controller *controller,
+-    struct hailo_vdma_engine *engine, u8 engine_index, u32 channels_bitmap)
+-{
+-    unsigned long irq_saved_flags = 0;
+-    // In case of FLR, the vdma registers will be NULL
+-    const bool is_device_up = (NULL != controller->dev);
+-
+-    hailo_vdma_engine_disable_channel_interrupts(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_dev_info(controller->dev, "Disabled interrupts for engine %u, channels bitmap 0x%x\n",
+-        engine_index, channels_bitmap);
+-}
+-
+ 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_interrupts_disable(controller, engine, engine_index, channels_bitmap);
++            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);
+         }
+     }
+@@ -178,10 +170,10 @@ long hailo_vdma_ioctl(struct hailo_vdma_
+     unsigned int cmd, unsigned long arg, struct file *filp, struct semaphore *mutex, bool *should_up_board_mutex)
+ {
+     switch (cmd) {
+-    case HAILO_VDMA_INTERRUPTS_ENABLE:
+-        return hailo_vdma_interrupts_enable_ioctl(controller, arg);
+-    case HAILO_VDMA_INTERRUPTS_DISABLE:
+-        return hailo_vdma_interrupts_disable_ioctl(controller, arg);
++    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:
+@@ -196,8 +188,8 @@ long hailo_vdma_ioctl(struct hailo_vdma_
+         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_BIND_VDMA_BUFFER:
+-        return hailo_desc_list_bind_vdma_buffer(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:
+@@ -216,28 +208,6 @@ long hailo_vdma_ioctl(struct hailo_vdma_
+     }
+ }
+-static int desc_list_mmap(struct hailo_vdma_controller *controller,
+-    struct hailo_descriptors_list_buffer *vdma_descriptors_buffer, struct vm_area_struct *vma)
+-{
+-    int err = 0;
+-    unsigned long vsize = vma->vm_end - vma->vm_start;
+-
+-    if (vsize > vdma_descriptors_buffer->buffer_size) {
+-        hailo_dev_err(controller->dev, "Requested size to map (%lx) is larger than the descriptor list size(%x)\n",
+-            vsize, vdma_descriptors_buffer->buffer_size);
+-        return -EINVAL;
+-    }
+-
+-    err = dma_mmap_coherent(controller->dev, vma, vdma_descriptors_buffer->kernel_address,
+-        vdma_descriptors_buffer->dma_address, vsize);
+-    if (err != 0) {
+-        hailo_dev_err(controller->dev, " Failed mmap descriptors %d\n", err);
+-        return err;
+-    }
+-
+-    return 0;
+-}
+-
+ static int low_memory_buffer_mmap(struct hailo_vdma_controller *controller,
+     struct hailo_vdma_low_memory_buffer *vdma_buffer, struct vm_area_struct *vma)
+ {
+@@ -300,15 +270,11 @@ static int continuous_buffer_mmap(struct
+ 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_descriptors_list_buffer *vdma_descriptors_buffer = NULL;
+     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 != (vdma_descriptors_buffer = hailo_vdma_find_descriptors_buffer(context, vdma_handle))) {
+-        return desc_list_mmap(controller, vdma_descriptors_buffer, vma);
+-    }
+-    else if (NULL != (low_memory_buffer = hailo_vdma_find_low_memory_buffer(context, 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))) {
+--- a/drivers/media/pci/hailo/vdma/vdma.h
++++ b/drivers/media/pci/hailo/vdma/vdma.h
+@@ -16,6 +16,8 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/types.h>
+ #include <linux/semaphore.h>
++#include <linux/dma-buf.h>
++#include <linux/version.h>
+ #define VDMA_CHANNEL_CONTROL_REG_OFFSET(channel_index, direction) (((direction) == DMA_TO_DEVICE) ? \
+             (((channel_index) << 5) + 0x0) : (((channel_index) << 5) + 0x10))
+@@ -28,6 +30,22 @@
+     ((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;
+@@ -35,7 +53,7 @@ struct hailo_vdma_buffer {
+     struct kref                 kref;
+     struct device               *device;
+-    void __user                 *user_address;
++    uintptr_t                   user_address;
+     u32                         size;
+     enum dma_data_direction     data_direction;
+     struct sg_table             sg_table;
+@@ -44,7 +62,10 @@ struct hailo_vdma_buffer {
+     // '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;
++    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.
+@@ -53,7 +74,7 @@ struct hailo_descriptors_list_buffer {
+     uintptr_t                          handle;
+     void                               *kernel_address;
+     dma_addr_t                         dma_address;
+-    u32                           buffer_size;
++    u32                                buffer_size;
+     struct hailo_vdma_descriptors_list desc_list;
+ };
+@@ -120,9 +141,6 @@ int hailo_vdma_controller_init(struct ha
+ void hailo_vdma_update_interrupts_mask(struct hailo_vdma_controller *controller,
+     size_t engine_index);
+-void hailo_vdma_engine_interrupts_disable(struct hailo_vdma_controller *controller,
+-    struct hailo_vdma_engine *engine, u8 engine_index, u32 channels_bitmap);
+-
+ 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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch b/target/linux/bcm27xx/patches-6.6/950-1236-media-rpivid-Make-SPS-PPS-optional-in-a-request.patch
new file mode 100644 (file)
index 0000000..26edb55
--- /dev/null
@@ -0,0 +1,80 @@
+From cf64a1dfecc2dc418efdd61701c1a4b185ab4761 Mon Sep 17 00:00:00 2001
+From: John Cox <jc@kynesim.co.uk>
+Date: Fri, 23 Aug 2024 16:48:38 +0100
+Subject: [PATCH 1236/1350] media/rpivid: Make SPS / PPS optional in a request
+
+SPS & PPS are optional in requests. Fix. The framework keeps the last
+value so this is mostly a matter of changing .required to false when
+requesting the controls. Check that SPS has ever been set on frame
+start, PPS is valid if all zeros so is at best tricky to check.
+
+Signed-off-by: John Cox <jc@kynesim.co.uk>
+---
+ drivers/staging/media/rpivid/rpivid.c       | 4 ++--
+ drivers/staging/media/rpivid/rpivid_h265.c  | 6 ++++++
+ drivers/staging/media/rpivid/rpivid_video.c | 5 -----
+ drivers/staging/media/rpivid/rpivid_video.h | 5 +++++
+ 4 files changed, 13 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/media/rpivid/rpivid.c
++++ b/drivers/staging/media/rpivid/rpivid.c
+@@ -40,14 +40,14 @@ static const struct rpivid_control rpivi
+                       .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 = {
+--- a/drivers/staging/media/rpivid/rpivid_h265.c
++++ b/drivers/staging/media/rpivid/rpivid_h265.c
+@@ -1726,6 +1726,12 @@ static void rpivid_h265_setup(struct rpi
+               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");
+--- a/drivers/staging/media/rpivid/rpivid_video.c
++++ b/drivers/staging/media/rpivid/rpivid_video.c
+@@ -257,11 +257,6 @@ static int rpivid_hevc_validate_sps(cons
+       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)
+ {
+--- a/drivers/staging/media/rpivid/rpivid_video.h
++++ b/drivers/staging/media/rpivid/rpivid_video.h
+@@ -20,6 +20,11 @@ struct rpivid_format {
+       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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch b/target/linux/bcm27xx/patches-6.6/950-1238-piscreen-overlay-Add-invert-x-y-and-swapxy.patch
new file mode 100644 (file)
index 0000000..0eeb8ae
--- /dev/null
@@ -0,0 +1,37 @@
+From 31be188fb945560c193020b19773625421847112 Mon Sep 17 00:00:00 2001
+From: Satadru Pramanik <satadru@gmail.com>
+Date: Wed, 4 Sep 2024 08:40:42 -0400
+Subject: [PATCH 1238/1350] piscreen-overlay: Add invert[x,y] and swapxy
+
+Signed-off-by: Satadru Pramanik <satadru@gmail.com>
+---
+ arch/arm/boot/dts/overlays/README               | 6 ++++++
+ arch/arm/boot/dts/overlays/piscreen-overlay.dts | 3 +++
+ 2 files changed, 9 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -3694,6 +3694,12 @@ Params: speed                   Display
+         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
+--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
+@@ -103,5 +103,8 @@
+               xohms =         <&piscreen_ts>,"ti,x-plate-ohms;0";
+               drm =           <&piscreen>,"compatible=waveshare,rpi-lcd-35",
+                               <&piscreen>,"reset-gpios:8=",<GPIO_ACTIVE_HIGH>;
++              invx =          <&piscreen_ts>,"touchscreen-inverted-x?";
++              invy =          <&piscreen_ts>,"touchscreen-inverted-y?";
++              swapxy =        <&piscreen_ts>,"touchscreen-swapped-x-y!";
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch b/target/linux/bcm27xx/patches-6.6/950-1239-drivers-gpu-drm-panel-Added-waveshare-5.0inch-6.25in.patch
new file mode 100644 (file)
index 0000000..96e3b47
--- /dev/null
@@ -0,0 +1,82 @@
+From f955b7838f9ce72e48b29e58d65e0642d097c8b3 Mon Sep 17 00:00:00 2001
+From: eng33 <eng33@waveshare.com>
+Date: Wed, 4 Sep 2024 10:48:22 +0800
+Subject: [PATCH 1239/1350] drivers:gpu:drm:panel: Added waveshare 5.0inch,
+ 6.25inch, and 8.8inch dsi screen devices
+
+Signed-off-by: eng33 <eng33@waveshare.com>
+---
+ drivers/gpu/drm/panel/panel-waveshare-dsi.c | 55 +++++++++++++++++++++
+ 1 file changed, 55 insertions(+)
+
+--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c
++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c
+@@ -150,6 +150,51 @@ static const struct drm_display_mode ws_
+       .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);
+@@ -413,6 +458,16 @@ static const struct of_device_id ws_pane
+               .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 */
+       }
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch b/target/linux/bcm27xx/patches-6.6/950-1240-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch
new file mode 100644 (file)
index 0000000..11f504a
--- /dev/null
@@ -0,0 +1,27 @@
+From 769cd349d65fb29aaa8f443f9c7a701205b0409c Mon Sep 17 00:00:00 2001
+From: eng33 <eng33@waveshare.com>
+Date: Wed, 4 Sep 2024 10:56:13 +0800
+Subject: [PATCH 1240/1350] arch:arm:boot:dts:overlays: Added waveshare
+ 5.0inch, 6.25inch, and 8.8inch dsi screen dts
+
+Signed-off-by: eng33 <eng33@waveshare.com>
+---
+ .../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts   | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- 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
+@@ -113,6 +113,13 @@
+               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";
diff --git a/target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch b/target/linux/bcm27xx/patches-6.6/950-1241-arch-arm-boot-dts-overlays-Added-waveshare-5.0inch-6.patch
new file mode 100644 (file)
index 0000000..0d59212
--- /dev/null
@@ -0,0 +1,23 @@
+From 3d39588b52abb06ed2b4b0d2db026133a920758b Mon Sep 17 00:00:00 2001
+From: eng33 <eng33@waveshare.com>
+Date: Thu, 5 Sep 2024 17:19:56 +0800
+Subject: [PATCH 1241/1350] arch:arm:boot:dts:overlays: Added waveshare
+ 5.0inch, 6.25inch, and 8.8inch dsi screen description
+
+Signed-off-by: eng33 <eng33@waveshare.com>
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -5233,6 +5233,9 @@ Params: 2_8_inch                2.8" 480
+         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
diff --git a/target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch b/target/linux/bcm27xx/patches-6.6/950-1242-spi-rp2040-gpio-bridge-Add-debugfs-progress-indicato.patch
new file mode 100644 (file)
index 0000000..4d7bc4d
--- /dev/null
@@ -0,0 +1,89 @@
+From 4d219b15a7a01a14c1be1eeee9a939732130d30a Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Tue, 13 Aug 2024 13:45:54 +0100
+Subject: [PATCH 1242/1350] spi: rp2040-gpio-bridge: Add debugfs progress
+ indicator
+
+Useful for tracking upload progress via userspace.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/spi/spi-rp2040-gpio-bridge.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/spi/spi-rp2040-gpio-bridge.c
++++ b/drivers/spi/spi-rp2040-gpio-bridge.c
+@@ -6,6 +6,7 @@
+  */
+ #include <crypto/hash.h>
++#include <linux/debugfs.h>
+ #include <linux/crypto.h>
+ #include <linux/delay.h>
+ #include <linux/firmware.h>
+@@ -91,6 +92,9 @@ enum rp2040_gbdg_fixed_size_commands {
+ 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;
+@@ -702,6 +706,7 @@ static int rp2040_gbdg_transfer_cached(s
+                       return 0;
+       }
++      priv_data->transfer_progress = 0;
+       while (length) {
+               unsigned int xfer = min(length, RP2040_GBDG_BLOCK_SIZE);
+@@ -710,7 +715,9 @@ static int rp2040_gbdg_transfer_cached(s
+                       return ret;
+               length -= xfer;
+               data += xfer;
++              priv_data->transfer_progress += xfer;
+       }
++      priv_data->transfer_progress = 0;
+       return 0;
+ }
+@@ -1016,6 +1023,16 @@ static int rp2040_gbdg_power_on(struct r
+       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;
+@@ -1023,6 +1040,7 @@ static int rp2040_gbdg_probe(struct i2c_
+       struct device *dev = &client->dev;
+       struct rp2040_gbdg *rp2040_gbdg;
+       struct device_node *np;
++      char debugfs_name[128];
+       int ret;
+       np = dev->of_node;
+@@ -1136,6 +1154,12 @@ static int rp2040_gbdg_probe(struct i2c_
+       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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch b/target/linux/bcm27xx/patches-6.6/950-1243-media-dt-bindings-i2c-Add-Sony-IMX500.patch
new file mode 100644 (file)
index 0000000..82e58c1
--- /dev/null
@@ -0,0 +1,166 @@
+From 30921ddfa24a5325d0f4980c72f98d20bace87a2 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Fri, 24 May 2024 11:43:07 +0100
+Subject: [PATCH 1243/1350] media: dt-bindings: i2c: Add Sony IMX500
+
+Add YAML device tree binding for the Sony IMX500 CMOS image sensor /
+CNN inference engine.  Also, add a MAINTAINERS entry.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ .../bindings/media/i2c/sony,imx500.yaml       | 132 ++++++++++++++++++
+ MAINTAINERS                                   |   7 +
+ 2 files changed, 139 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx500.yaml
+
+--- /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 <kernel-list@raspberrypi.com>
++
++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 <dt-bindings/gpio/gpio.h>
++
++    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>;
++          };
++        };
++      };
++    };
++
++...
++
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -20127,6 +20127,13 @@ F:    Documentation/devicetree/bindings/med
+ F:    Documentation/devicetree/bindings/media/i2c/imx477.yaml
+ F:    drivers/media/i2c/imx477.c
++SONY IMX500 SENSOR DRIVER
++M:    Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
++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
++
+ SONY IMX519 SENSOR DRIVER
+ M:    Arducam Kernel Maintenance <info@arducam.com>
+ L:    linux-media@vger.kernel.org
diff --git a/target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch b/target/linux/bcm27xx/patches-6.6/950-1244-media-i2c-Add-driver-for-Sony-IMX500-sensor.patch
new file mode 100644 (file)
index 0000000..331e586
--- /dev/null
@@ -0,0 +1,1675 @@
+From f9b1e0ffdd9b5134d9356d7e09e9c1a065fdfa13 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Thu, 27 Jun 2024 10:11:44 +0100
+Subject: [PATCH 1244/1350] media: i2c: Add driver for Sony IMX500 sensor
+
+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. This driver supports imaging only.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ MAINTAINERS                |    1 +
+ drivers/media/i2c/Kconfig  |   12 +
+ drivers/media/i2c/Makefile |    1 +
+ drivers/media/i2c/imx500.c | 1610 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1624 insertions(+)
+ create mode 100644 drivers/media/i2c/imx500.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -20133,6 +20133,7 @@ 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 <info@arducam.com>
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -236,6 +236,18 @@ config VIDEO_IMX477
+         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
+--- a/drivers/media/i2c/Makefile
++++ b/drivers/media/i2c/Makefile
+@@ -58,6 +58,7 @@ 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
+--- /dev/null
++++ b/drivers/media/i2c/imx500.c
+@@ -0,0 +1,1610 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * A V4L2 driver for Sony IMX500 cameras.
++ * Copyright (C) 2024, Raspberry Pi Ltd
++ */
++#include <asm/unaligned.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/regulator/consumer.h>
++#include <media/v4l2-cci.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-fwnode.h>
++#include <media/v4l2-mediabus.h>
++
++/* 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 4
++
++/* 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
++
++/* 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))
++
++/* 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
++
++#define NUM_PADS 1
++
++/* 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)
++
++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 framerate. */
++      unsigned int framerate_default;
++
++      /* 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(0x0138), 0x01 }, /* TEMP_SENS_CTL */
++      { CCI_REG8(0x0112), 0x0a },
++      { CCI_REG8(0x0113), 0x0a },
++      { CCI_REG8(0x0114), 0x01 }, /* CSI_LANE_MODE */
++};
++
++/* 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 },
++};
++
++/* 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,
++              },
++              .framerate_default = 10,
++              .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,
++              },
++              .framerate_default = 40,
++              .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,
++};
++
++struct imx500 {
++      struct v4l2_subdev sd;
++      struct media_pad pad;
++      struct regmap *regmap;
++
++      unsigned int fmt_code;
++
++      struct clk *xclk;
++      u32 xclk_freq;
++
++      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;
++
++      /* 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;
++
++      /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
++      unsigned int long_exp_shift;
++};
++
++static inline struct imx500 *to_imx500(struct v4l2_subdev *_sd)
++{
++      return container_of(_sd, struct imx500, sd);
++}
++
++/* 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;
++}
++
++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);
++}
++
++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;
++
++      /*
++       * 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;
++      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->index != 0)
++              return -EINVAL;
++
++      code->code = imx500_get_format_code(imx500);
++
++      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;
++
++      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;
++
++      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 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 = imx500_get_format_code(imx500);
++              fmt->format = *try_fmt;
++      } else {
++              imx500_update_image_pad_format(imx500, imx500->mode, fmt);
++              fmt->format.code = imx500_get_format_code(imx500);
++      }
++
++      mutex_unlock(&imx500->mutex);
++      return 0;
++}
++
++static unsigned int imx500_get_frame_length(const struct imx500_mode *mode,
++                                          unsigned int framerate_default)
++{
++      u64 frame_length;
++
++      frame_length = IMX500_PIXEL_RATE;
++      do_div(frame_length, (u64)framerate_default * mode->line_length_pix);
++
++      if (WARN_ON(frame_length > IMX500_FRAME_LENGTH_MAX))
++              frame_length = IMX500_FRAME_LENGTH_MAX;
++
++      return max_t(unsigned int, frame_length, mode->height);
++}
++
++static void imx500_set_framing_limits(struct imx500 *imx500)
++{
++      unsigned int frm_length_default, hblank_min;
++      const struct imx500_mode *mode = imx500->mode;
++
++      frm_length_default =
++              imx500_get_frame_length(mode, mode->framerate_default);
++
++      /* Default to no long exposure multiplier. */
++      imx500->long_exp_shift = 0;
++
++      /* Update limits and set FPS to default */
++      __v4l2_ctrl_modify_range(
++              imx500->vblank, 1,
++              ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) -
++                      mode->height,
++              IMX500_VBLANK_MIN, frm_length_default - mode->height);
++
++      /* Setting this will adjust the exposure limits as well. */
++      __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height);
++
++      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);
++
++      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);
++      }
++
++      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;
++}
++
++/* 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_IMAGE_ONLY_TRUE,
++                      NULL);
++      if (ret) {
++              dev_err(&client->dev, "%s failed to set image mode\n",
++                      __func__);
++              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;
++      }
++
++      /* 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__);
++
++      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);
++
++      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->common_regs_written = false;
++
++      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,
++};
++
++/* 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, 0, 0xffff, 1, 0);
++      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);
++
++      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 imx500_probe(struct i2c_client *client)
++{
++      struct device *dev = &client->dev;
++      struct imx500 *imx500;
++      int ret;
++
++      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");
++
++      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->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.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;
++      }
++
++      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);
++
++      v4l2_async_unregister_subdev(sd);
++      media_entity_cleanup(&sd->entity);
++      imx500_free_controls(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,
++};
++
++module_i2c_driver(imx500_i2c_driver);
++
++MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
++MODULE_DESCRIPTION("Sony IMX500 sensor driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch b/target/linux/bcm27xx/patches-6.6/950-1245-lib-earlycpio-export-symbol-find_cpio_data.patch
new file mode 100644 (file)
index 0000000..f749e84
--- /dev/null
@@ -0,0 +1,20 @@
+From a32f7dae82774d6064181dcc989c1c1349c4e47e Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Thu, 20 Jun 2024 09:58:32 +0100
+Subject: [PATCH 1245/1350] lib: earlycpio: export symbol find_cpio_data()
+
+Add EXPORT_SYMBOL_GPL() for find_cpio_data() so that loadable modules
+may also parse uncompressed cpio.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ lib/earlycpio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/lib/earlycpio.c
++++ b/lib/earlycpio.c
+@@ -139,3 +139,4 @@ struct cpio_data find_cpio_data(const ch
+ quit:
+       return cd;
+ }
++EXPORT_SYMBOL_GPL(find_cpio_data);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch b/target/linux/bcm27xx/patches-6.6/950-1246-media-i2c-imx500-Inbuilt-AI-processor-support.patch
new file mode 100644 (file)
index 0000000..9a0642b
--- /dev/null
@@ -0,0 +1,1631 @@
+From 97f4ec49828877642e4a87f9c2f47c7a9dd10b90 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Wed, 24 Jul 2024 13:06:16 +0100
+Subject: [PATCH 1246/1350] media: i2c: imx500: Inbuilt AI processor support
+
+Add support for the IMX500's inbuilt AI processor. The IMX500 program
+loader, AI processor firmware, DNN weights are accessed via the kernel's
+firmware interface on 'open' and are transferred to the IMX500 over SPI.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ drivers/media/i2c/imx500.c         | 1322 +++++++++++++++++++++++++++-
+ include/uapi/linux/v4l2-controls.h |    6 +
+ 2 files changed, 1290 insertions(+), 38 deletions(-)
+
+--- a/drivers/media/i2c/imx500.c
++++ b/drivers/media/i2c/imx500.c
+@@ -5,9 +5,14 @@
+  */
+ #include <asm/unaligned.h>
+ #include <linux/clk.h>
++#include <linux/debugfs.h>
+ #include <linux/delay.h>
++#include <linux/earlycpio.h>
++#include <linux/firmware.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/i2c.h>
++#include <linux/kernel_read_file.h>
++#include <linux/limits.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
+ #include <linux/pm_runtime.h>
+@@ -67,6 +72,138 @@
+ #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)
+@@ -81,6 +218,11 @@
+ #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
+@@ -89,7 +231,12 @@
+ #define IMX500_PIXEL_ARRAY_WIDTH 4056U
+ #define IMX500_PIXEL_ARRAY_HEIGHT 3040U
+-#define NUM_PADS 1
++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[] = {
+@@ -101,6 +248,13 @@ static const char *const imx500_supply_n
+ #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;
+@@ -135,10 +289,19 @@ static const struct cci_reg_sequence mod
+       { CCI_REG8(0x0106), 0x01 }, /* FAST_STANDBY_CTL */
+       { CCI_REG8(0x0136), 0x1b }, /* EXCLK_FREQ */
+       { CCI_REG8(0x0137), 0x00 },
+-      { CCI_REG8(0x0138), 0x01 }, /* TEMP_SENS_CTL */
+       { 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 */
+@@ -624,6 +787,111 @@ static const struct cci_reg_sequence mod
+       { 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 },
++};
++
+ /* Mode configs */
+ static const struct imx500_mode imx500_supported_modes[] = {
+       {
+@@ -679,9 +947,17 @@ static const u32 codes[] = {
+       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;
++      struct media_pad pad[NUM_PADS];
+       struct regmap *regmap;
+       unsigned int fmt_code;
+@@ -701,6 +977,9 @@ struct imx500 {
+       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;
+@@ -717,8 +996,24 @@ struct imx500 {
+       /* 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)
+@@ -726,6 +1021,188 @@ static inline struct imx500 *to_imx500(s
+       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)
+ {
+@@ -745,6 +1222,144 @@ static void imx500_set_default_format(st
+       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, &reg);
++              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;
+@@ -777,6 +1392,99 @@ static int imx500_set_frame_length(struc
+                        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 =
+@@ -784,6 +1492,53 @@ static int imx500_set_ctrl(struct v4l2_c
+       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.
+@@ -831,6 +1586,11 @@ static int imx500_set_ctrl(struct v4l2_c
+               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,
+@@ -870,10 +1630,17 @@ static int imx500_enum_mbus_code(struct
+       if (code->pad >= NUM_PADS)
+               return -EINVAL;
+-      if (code->index != 0)
+-              return -EINVAL;
++      if (code->pad == IMAGE_PAD) {
++              if (code->index != 0)
++                      return -EINVAL;
+-      code->code = imx500_get_format_code(imx500);
++              code->code = imx500_get_format_code(imx500);
++      } else {
++              if (code->index > 0)
++                      return -EINVAL;
++
++              code->code = MEDIA_BUS_FMT_SENSOR_DATA;
++      }
+       return 0;
+ }
+@@ -887,19 +1654,31 @@ static int imx500_enum_frame_size(struct
+       if (fse->pad >= NUM_PADS)
+               return -EINVAL;
+-      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;
++      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 = 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;
++              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;
+ }
+@@ -920,6 +1699,17 @@ static void imx500_update_image_pad_form
+               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)
+@@ -935,11 +1725,18 @@ static int imx500_get_pad_format(struct
+               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 = imx500_get_format_code(imx500);
++              try_fmt->code = fmt->pad == IMAGE_PAD ?
++                                      imx500_get_format_code(imx500) :
++                                      MEDIA_BUS_FMT_SENSOR_DATA;
+               fmt->format = *try_fmt;
+       } else {
+-              imx500_update_image_pad_format(imx500, imx500->mode, fmt);
+-              fmt->format.code = imx500_get_format_code(imx500);
++              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);
+@@ -1000,22 +1797,35 @@ static int imx500_set_pad_format(struct
+       mutex_lock(&imx500->mutex);
+-      const struct imx500_mode *mode_list = imx500_supported_modes;
+-      unsigned int num_modes = ARRAY_SIZE(imx500_supported_modes);
++      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);
++              /* 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);
++              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);
+@@ -1074,6 +1884,243 @@ static int imx500_get_selection(struct v
+       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 */
++              ret = imx500_spi_write(imx500, data, size);
++              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)
+ {
+@@ -1086,7 +2133,8 @@ static int imx500_start_streaming(struct
+               return ret;
+       ret = cci_write(imx500->regmap, IMX500_REG_IMAGE_ONLY_MODE,
+-                      IMX500_IMAGE_ONLY_TRUE,
++                      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",
+@@ -1094,6 +2142,30 @@ static int imx500_start_streaming(struct
+               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);
+@@ -1107,6 +2179,38 @@ static int imx500_start_streaming(struct
+               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,
+@@ -1141,6 +2245,11 @@ static void imx500_stop_streaming(struct
+       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);
+ }
+@@ -1173,6 +2282,7 @@ static int imx500_set_stream(struct v4l2
+       /* 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);
+@@ -1247,7 +2357,10 @@ static int imx500_power_off(struct devic
+       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;
+ }
+@@ -1317,6 +2430,36 @@ 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)
+ {
+@@ -1376,6 +2519,9 @@ static int imx500_init_controls(struct i
+               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;
+@@ -1459,12 +2605,35 @@ error_out:
+       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;
+@@ -1474,6 +2643,8 @@ static int imx500_probe(struct i2c_clien
+               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 */
+@@ -1534,10 +2705,10 @@ static int imx500_probe(struct i2c_clien
+       imx500->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       /* Initialize source pads */
+-      imx500->pad.flags = MEDIA_PAD_FL_SOURCE;
++      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);
++      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;
+@@ -1549,6 +2720,12 @@ static int imx500_probe(struct i2c_clien
+               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);
+@@ -1573,10 +2750,23 @@ static void imx500_remove(struct i2c_cli
+       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);
+@@ -1603,7 +2793,63 @@ static struct i2c_driver imx500_i2c_driv
+       .remove = imx500_remove,
+ };
+-module_i2c_driver(imx500_i2c_driver);
++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 <naush@raspberrypi.com>");
+ MODULE_DESCRIPTION("Sony IMX500 sensor driver");
+--- a/include/uapi/linux/v4l2-controls.h
++++ b/include/uapi/linux/v4l2-controls.h
+@@ -207,6 +207,12 @@ enum v4l2_colorfx {
+  * 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 */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch b/target/linux/bcm27xx/patches-6.6/950-1247-dts-bcm-283x-2712-clocks-as-simple-bus.patch
new file mode 100644 (file)
index 0000000..ec77dd1
--- /dev/null
@@ -0,0 +1,41 @@
+From 15cc525406cf311399d182ffcc18711651b7c8b2 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Fri, 12 Jul 2024 13:32:30 +0100
+Subject: [PATCH 1247/1350] dts: bcm{283x,2712}: /clocks as "simple-bus"
+
+Make /clocks node compatible with "simple-bus" to ensure that all children
+(not just those that are "fixed-clock" compatible) are automatically
+probed.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ arch/arm/boot/dts/broadcom/bcm283x.dtsi   | 4 ++++
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 4 ++++
+ 2 files changed, 8 insertions(+)
+
+--- a/arch/arm/boot/dts/broadcom/bcm283x.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm283x.dtsi
+@@ -478,6 +478,10 @@
+       };
+       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";
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -1258,6 +1258,10 @@
+       };
+       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";
diff --git a/target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch b/target/linux/bcm27xx/patches-6.6/950-1248-dts-Add-AI-Camera-support.patch
new file mode 100644 (file)
index 0000000..4a45148
--- /dev/null
@@ -0,0 +1,389 @@
+From 4113b1097fe40ff3a64ee7a9ade7c258e9ecdb5b Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Mon, 3 Jun 2024 14:10:27 +0100
+Subject: [PATCH 1248/1350] dts: Add 'AI Camera' support
+
+The AI Camera combines an IMX500 and a RP2040 GPIO bridge on a single
+module. The Raspberry Pi camera regulator is used for both IMX500 and
+RP2040. SPI, clocks, and reset (required by IMX500) are provided by the
+RP2040 GPIO bridge.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/Makefile           |   2 +
+ arch/arm/boot/dts/overlays/README             |  21 +++
+ arch/arm/boot/dts/overlays/imx500-overlay.dts | 119 +++++++++++++++++
+ .../boot/dts/overlays/imx500-pi5-overlay.dts  | 124 ++++++++++++++++++
+ arch/arm/boot/dts/overlays/imx500.dtsi        |  28 ++++
+ arch/arm/boot/dts/overlays/overlay_map.dts    |  10 ++
+ .../dts/overlays/rpi-rp2040-gpio-bridge.dtsi  |  21 +++
+ 7 files changed, 325 insertions(+)
+ 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/rpi-rp2040-gpio-bridge.dtsi
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -136,6 +136,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       imx378.dtbo \
+       imx462.dtbo \
+       imx477.dtbo \
++      imx500.dtbo \
++      imx500-pi5.dtbo \
+       imx519.dtbo \
+       imx708.dtbo \
+       interludeaudio-analog.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2818,6 +2818,27 @@ Params: rotation                Mounting
+         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,<param>=<val>
++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
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts
+@@ -0,0 +1,119 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Definitions for IMX500 camera module on VC I2C bus
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/{
++      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;
++              };
++      };
++
++      clocks_frag: fragment@104 {
++              target-path = "/clocks";
++              __overlay__ {
++                      clk_aicam: clk-aicam {
++                              compatible = "fixed-clock";
++                              #clock-cells = <0>;
++                              clock-frequency = <24000000>;
++                      };
++
++                      clk_aicam_gated: clk-aicam-gated {
++                              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>,
++                     <&reg_frag>, "target:0=",<&cam0_reg>,
++                     <&cam_node>, "VANA-supply:0=",<&cam0_reg>;
++              bypass-cache = <&spi_bridge>,"bypass-cache?";
++      };
++};
++
++&cam_node {
++      status = "okay";
++      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>;
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts
+@@ -0,0 +1,124 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Definitions for IMX500 camera module on VC I2C bus
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/{
++      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";
++              };
++      };
++
++      clocks_frag: fragment@104 {
++              target-path = "/clocks";
++              __overlay__ {
++                      clk_aicam: clk-aicam {
++                              compatible = "fixed-clock";
++                              #clock-cells = <0>;
++                              clock-frequency = <24000000>;
++                      };
++
++                      clk_aicam_gated: clk-aicam-gated {
++                              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>,
++                     <&reg_frag>, "target:0=",<&cam0_reg>,
++                     <&cam_node>, "VANA-supply:0=",<&cam0_reg>;
++              bypass-cache = <&spi_bridge>,"bypass-cache?";
++      };
++};
++
++&cam_node {
++      status = "okay";
++      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>;
++};
+--- /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>;
++              };
++      };
++};
+--- a/arch/arm/boot/dts/overlays/overlay_map.dts
++++ b/arch/arm/boot/dts/overlays/overlay_map.dts
+@@ -118,6 +118,16 @@
+               bcm2711;
+       };
++      imx500 {
++              bcm2835;
++              bcm2711;
++              bcm2712 = "imx500-pi5";
++      };
++
++      imx500-pi5 {
++              bcm2712;
++      };
++
+       lirc-rpi {
+               deprecated = "use gpio-ir";
+       };
+--- /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/target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch b/target/linux/bcm27xx/patches-6.6/950-1250-media-i2c-imx500-Enable-LED-during-SPI-transfers.patch
new file mode 100644 (file)
index 0000000..cd7da62
--- /dev/null
@@ -0,0 +1,66 @@
+From 62faabb61ae152e8289a00ffb3445f4c47777b33 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Mon, 3 Jun 2024 16:02:41 +0100
+Subject: [PATCH 1250/1350] media: i2c: imx500: Enable LED during SPI transfers
+
+The Raspberry Pi 'AI Camera' is equipped with an LED. Enable this LED
+during SPI transfers to indicate to the end-user that progress is being
+made during large tramsfers.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/imx500-overlay.dts     | 1 +
+ arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts | 1 +
+ drivers/media/i2c/imx500.c                        | 6 ++++++
+ 3 files changed, 8 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/imx500-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts
+@@ -105,6 +105,7 @@
+ &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>;
+--- a/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts
+@@ -110,6 +110,7 @@
+ &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>;
+--- a/drivers/media/i2c/imx500.c
++++ b/drivers/media/i2c/imx500.c
+@@ -965,6 +965,7 @@ struct imx500 {
+       struct clk *xclk;
+       u32 xclk_freq;
++      struct gpio_desc *led_gpio;
+       struct gpio_desc *reset_gpio;
+       struct regulator_bulk_data supplies[IMX500_NUM_SUPPLIES];
+@@ -1990,7 +1991,10 @@ static int imx500_state_transition(struc
+               }
+               /* 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)
+@@ -2670,6 +2674,8 @@ static int imx500_probe(struct i2c_clien
+               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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch b/target/linux/bcm27xx/patches-6.6/950-1251-spi-rp2040-gpio-bridge-add-missing-MD5-dependency.patch
new file mode 100644 (file)
index 0000000..f6a27b8
--- /dev/null
@@ -0,0 +1,24 @@
+From cc50cdbcf3e8f065bd7798a92689f54578b4169f Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+Date: Wed, 24 Jul 2024 15:48:22 +0100
+Subject: [PATCH 1251/1350] spi: rp2040-gpio-bridge: add missing MD5 dependency
+
+rp2040-gpio-bridge relies on the md5 crypto driver. This dependency
+cannot be determined automatically as rp2040-gpio-bridge does not
+use any of md5's symbols directly.
+
+Declare a soft 'pre' dependency on md5 to ensure that it is included and
+loaded before rp2040-gpio-bridge.
+
+Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
+---
+ drivers/spi/spi-rp2040-gpio-bridge.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spi-rp2040-gpio-bridge.c
++++ b/drivers/spi/spi-rp2040-gpio-bridge.c
+@@ -1241,3 +1241,4 @@ module_i2c_driver(rp2040_gbdg_driver);
+ MODULE_AUTHOR("Richard Oliver <richard.oliver@raspberrypi.com>");
+ MODULE_DESCRIPTION("Raspberry Pi RP2040 GPIO Bridge");
+ MODULE_LICENSE("GPL");
++MODULE_SOFTDEP("pre: md5");
diff --git a/target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch b/target/linux/bcm27xx/patches-6.6/950-1252-drivers-drm-rp1-vec-Increase-width-limit-for-PAL-16-.patch
new file mode 100644 (file)
index 0000000..d22b3c0
--- /dev/null
@@ -0,0 +1,50 @@
+From eab19e7bde679f56241db0c51f94f056fcffd6a9 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+Date: Wed, 4 Sep 2024 19:28:50 +0100
+Subject: [PATCH 1252/1350] drivers: drm: rp1-vec: Increase width limit, for
+ PAL 16:9 @ 18MHz
+
+There was no technical reason for the DRM mode's width limit of 848;
+increase it to 960 (720*18MHz/13.5MHz) to support ~square pixels on
+16:9 screens. Tweak the PAL active window to start slightly earlier.
+(The maximum number of visible columns at 18MHz is about 942.)
+
+Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+---
+ drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c    | 4 ++--
+ drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec.c
+@@ -508,8 +508,8 @@ static int rp1vec_platform_probe(struct
+       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;
+--- a/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
++++ b/drivers/gpu/drm/rp1/rp1-vec/rp1_vec_hw.c
+@@ -195,7 +195,7 @@ static const struct rp1vec_hwmode rp1vec
+                       .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,
+@@ -218,7 +218,7 @@ static const struct rp1vec_hwmode rp1vec
+                       .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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch b/target/linux/bcm27xx/patches-6.6/950-1255-Revert-Bluetooth-Always-request-for-user-confirmatio.patch
new file mode 100644 (file)
index 0000000..e549f27
--- /dev/null
@@ -0,0 +1,45 @@
+From d6a12dd8f4e9362f7dd355969dd046adc44b1f47 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 1 Mar 2021 09:12:44 +0000
+Subject: [PATCH 1255/1350] Revert "Bluetooth: Always request for user
+ confirmation for Just Works (LE SC)"
+
+This reverts commit ffee202a78c2980688bc5d2f7d56480e69a5e0c9.
+
+The commit "Bluetooth: Always request for user confirmation for Just
+Works" prevents BLE devices pairing in (at least) the Raspberry Pi OS
+GUI. After reverting it, pairing works again. Although this companion
+commit ("... (LE SC)") has not been demonstrated to be problematic,
+it follows the same logic and therefore could affect some use cases.
+
+If another solution to the problem is found then this reversion will
+be removed.
+
+See: https://github.com/raspberrypi/linux/issues/4139
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ net/bluetooth/smp.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/net/bluetooth/smp.c
++++ b/net/bluetooth/smp.c
+@@ -2208,7 +2208,7 @@ mackey_and_ltk:
+       if (err)
+               return SMP_UNSPECIFIED;
+-      if (smp->method == REQ_OOB) {
++      if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
+               if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
+                       sc_dhkey_check(smp);
+                       SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+@@ -2223,9 +2223,6 @@ mackey_and_ltk:
+       confirm_hint = 0;
+ confirm:
+-      if (smp->method == JUST_WORKS)
+-              confirm_hint = 1;
+-
+       err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
+                                       hcon->dst_type, passkey, confirm_hint);
+       if (err)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch b/target/linux/bcm27xx/patches-6.6/950-1256-media-i2c-ov5647-Add-control-of-V4L2_CID_HBLANK.patch
new file mode 100644 (file)
index 0000000..89c690c
--- /dev/null
@@ -0,0 +1,126 @@
+From e4c2a7731efcd7abe7554debef783b5358712d6d Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 9 Sep 2024 16:41:12 +0100
+Subject: [PATCH 1256/1350] media: i2c: ov5647: Add control of V4L2_CID_HBLANK
+
+The driver did expose V4L2_CID_HBLANK, but as a READ_ONLY control.
+
+The sensor only uses the HTS register to control the line length,
+so convert this control to read/write, with the appropriate ranges.
+Adopt the old fixed values as the minimum values permitted in each
+mode to avoid issues of it not streaming.
+
+This should allow exposure times up to ~3 seconds (up from ~1sec).
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -53,6 +53,8 @@
+ #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
+@@ -79,6 +81,8 @@
+ #define OV5647_VBLANK_MIN             24
+ #define OV5647_VTS_MAX                        32767
++#define OV5647_HTS_MAX                        0x1fff
++
+ #define OV5647_EXPOSURE_MIN           4
+ #define OV5647_EXPOSURE_STEP          1
+ #define OV5647_EXPOSURE_DEFAULT               1000
+@@ -188,8 +192,6 @@ static struct regval_list ov5647_2592x19
+       {0x3a19, 0xf8},
+       {0x3c01, 0x80},
+       {0x3b07, 0x0c},
+-      {0x380c, 0x0b},
+-      {0x380d, 0x1c},
+       {0x3814, 0x11},
+       {0x3815, 0x11},
+       {0x3708, 0x64},
+@@ -277,8 +279,6 @@ static struct regval_list ov5647_1080p30
+       {0x3a19, 0xf8},
+       {0x3c01, 0x80},
+       {0x3b07, 0x0c},
+-      {0x380c, 0x09},
+-      {0x380d, 0x70},
+       {0x3814, 0x11},
+       {0x3815, 0x11},
+       {0x3708, 0x64},
+@@ -376,8 +376,6 @@ static struct regval_list ov5647_2x2binn
+       {0x3809, 0x10},
+       {0x380a, 0x03},
+       {0x380b, 0xcc},
+-      {0x380c, 0x07},
+-      {0x380d, 0x68},
+       {0x3811, 0x0c},
+       {0x3813, 0x06},
+       {0x3814, 0x31},
+@@ -451,8 +449,6 @@ static struct regval_list ov5647_640x480
+       {0x3a19, 0xf8},
+       {0x3c01, 0x80},
+       {0x3b07, 0x0c},
+-      {0x380c, 0x07},
+-      {0x380d, 0x3c},
+       {0x3814, 0x35},
+       {0x3815, 0x35},
+       {0x3708, 0x64},
+@@ -1079,7 +1075,8 @@ static int ov5647_set_pad_fmt(struct v4l
+                                        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;
+@@ -1343,6 +1340,10 @@ static int ov5647_s_ctrl(struct v4l2_ctr
+               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]);
+@@ -1350,7 +1351,6 @@ static int ov5647_s_ctrl(struct v4l2_ctr
+       /* 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;
+@@ -1427,10 +1427,11 @@ static int ov5647_init_controls(struct o
+                                              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,
+@@ -1464,7 +1465,6 @@ static int ov5647_init_controls(struct o
+               goto handler_free;
+       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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch b/target/linux/bcm27xx/patches-6.6/950-1257-drm-vc4-Add-support-for-per-plane-scaling-filter-sel.patch
new file mode 100644 (file)
index 0000000..5b3ae3c
--- /dev/null
@@ -0,0 +1,170 @@
+From d6a3a3f106010d9576a700148220842cac4c5739 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 25 Jul 2024 15:42:41 +0100
+Subject: [PATCH 1257/1350] drm/vc4: Add support for per plane scaling filter
+ selection
+
+Seeing as the HVS can be configured with regard the scaling filter,
+and DRM now supports selecting scaling filters at a per CRTC or
+per plane level, we can implement it.
+
+Default remains as the Mitchell/Netravali filter, but nearest
+neighbour is now also implemented.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_drv.h   |  1 +
+ drivers/gpu/drm/vc4/vc4_hvs.c   | 14 ++++++++--
+ drivers/gpu/drm/vc4/vc4_plane.c | 48 ++++++++++++++++++++++++++-------
+ 3 files changed, 52 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -358,6 +358,7 @@ struct vc4_hvs {
+       struct work_struct free_dlist_work;
+       struct drm_mm_node mitchell_netravali_filter;
++      struct drm_mm_node nearest_neighbour_filter;
+       struct debugfs_regset32 regset;
+--- a/drivers/gpu/drm/vc4/vc4_hvs.c
++++ b/drivers/gpu/drm/vc4/vc4_hvs.c
+@@ -469,6 +469,9 @@ static int vc4_hvs_debugfs_dlist_allocs(
+ 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,
+@@ -2255,14 +2258,19 @@ static int vc4_hvs_bind(struct device *d
+       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)
+@@ -2288,6 +2296,8 @@ static void vc4_hvs_unbind(struct device
+       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);
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -582,7 +582,9 @@ static void vc4_write_tpz(struct vc4_pla
+ /* 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)
+ {
+       struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev);
+       u32 scale = src / dst;
+@@ -621,6 +623,7 @@ static void vc4_write_ppf(struct vc4_pla
+       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) |
+                       /*
+@@ -815,15 +818,17 @@ static void vc4_write_scaling_parameters
+       /* Ch0 H-PPF Word 0: Scaling Parameters */
+       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_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_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);
+       }
+@@ -1573,7 +1578,18 @@ static int vc4_plane_mode_set(struct drm
+                   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 */
+@@ -1984,9 +2000,19 @@ static int vc6_plane_mode_set(struct drm
+                   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);
+@@ -2468,6 +2494,10 @@ struct drm_plane *vc4_plane_init(struct
+                                         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)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch b/target/linux/bcm27xx/patches-6.6/950-1258-drm-panel-waveshare-Remove-duplicated-sentinel-on-co.patch
new file mode 100644 (file)
index 0000000..215cc3c
--- /dev/null
@@ -0,0 +1,37 @@
+From 7a3d1c22ecbdac458883991beae0461137cbfc8a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 12 Sep 2024 18:04:58 +0100
+Subject: [PATCH 1258/1350] drm: panel: waveshare: Remove duplicated sentinel
+ on compatible list
+
+Remove the duplicated sentinel that got added, otherwise we have
+an extra blank compatible string match in the module, and that matches
+everything.
+
+$ modinfo panel_waveshare_dsi
+filename:       /lib/modules/6.6.50-v8+/kernel/drivers/gpu/drm/panel/panel-waveshare-dsi.ko.xz
+license:        GPL
+description:    Waveshare DSI panel driver
+author:         Dave Stevenson <dave.stevenson@raspberrypi.com>
+srcversion:     E767180DABD8B00B45571AF
+alias:          of:N*T*C*
+alias:          of:N*T*
+alias:          of:N*T*Cwaveshare,8.8inch-panelC*
+alias:          of:N*T*Cwaveshare,8.8inch-panel
+
+Fixes: f955b7838f9c ("drivers:gpu:drm:panel: Added waveshare 5.0inch, 6.25inch, and 8.8inch dsi screen devices")
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/panel/panel-waveshare-dsi.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/gpu/drm/panel/panel-waveshare-dsi.c
++++ b/drivers/gpu/drm/panel/panel-waveshare-dsi.c
+@@ -467,7 +467,6 @@ static const struct of_device_id ws_pane
+               .compatible = "waveshare,8.8inch-panel",
+               .data = &ws_panel_8_8_mode,
+       }, {
+-      }, {
+               /* sentinel */
+       }
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch b/target/linux/bcm27xx/patches-6.6/950-1260-drivers-mmc-disable-write-caching-on-Samsung-2023-mo.patch
new file mode 100644 (file)
index 0000000..35607aa
--- /dev/null
@@ -0,0 +1,47 @@
+From c9b61d1d83073761871c7acba332216494e6f0bb Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Mon, 8 Apr 2024 16:09:52 +0100
+Subject: [PATCH 1260/1350] drivers: mmc: disable write-caching on Samsung 2023
+ model year SD cards
+
+Samsung EVO Plus, Pro Plus and Evo Ultimate cards of this era appear to
+have a broken cache-flush implementation when operating in CQ mode.
+
+Unfortunately the cards seem to use a separate CID name string for every
+variant and capacity, so nobble the cache feature for this MANFID, OEMID
+and year. Turning this off seems to have negligible impact on
+random-write throughput in non-CQ mode.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/card.h   | 1 +
+ drivers/mmc/core/quirks.h | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/mmc/core/card.h
++++ b/drivers/mmc/core/card.h
+@@ -84,6 +84,7 @@ struct mmc_fixup {
+ #define CID_MANFID_TOSHIBA      0x11
+ #define CID_MANFID_MICRON       0x13
+ #define CID_MANFID_SAMSUNG      0x15
++#define CID_MANFID_SAMSUNG_SD 0x1b
+ #define CID_MANFID_APACER       0x27
+ #define CID_MANFID_KINGSTON     0x70
+ #define CID_MANFID_HYNIX      0x90
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -25,6 +25,14 @@ static const struct mmc_fixup __maybe_un
+                  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.
++       */
++      _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_SAMSUNG_SD, 0x534d, 2023, 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
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch b/target/linux/bcm27xx/patches-6.6/950-1261-mm-vmscan-Maintain-TLB-coherency-in-LRU-code.patch
new file mode 100644 (file)
index 0000000..70ece97
--- /dev/null
@@ -0,0 +1,27 @@
+From 536f2097dc397e4ebd0566e8f00219c02d7c8073 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 12 Sep 2024 10:06:50 +0100
+Subject: [PATCH 1261/1350] mm/vmscan: Maintain TLB coherency in LRU code
+
+As a workaround (and possibly a fix) for CPU spins observed on BCM2837,
+use ptep_clear_flush_young instead of ptep_test_and_clear_young inside
+lru_gen_look_around in order to expose PTE changes to the MMU. Note that
+on architectures that don't require an explicit flush,
+ptep_clear_flush_young just calls ptep_test_and_clear_young.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ mm/vmscan.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -4716,7 +4716,7 @@ void lru_gen_look_around(struct page_vma
+               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/target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch b/target/linux/bcm27xx/patches-6.6/950-1262-drm-panel-ili9881-Correct-symmetry-on-enable-disable.patch
new file mode 100644 (file)
index 0000000..d10eee3
--- /dev/null
@@ -0,0 +1,35 @@
+From c763cf351ea25b7fb31f2d388dab0838565d1b75 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 13 Sep 2024 14:44:08 +0100
+Subject: [PATCH 1262/1350] drm: panel: ili9881: Correct symmetry on
+ enable/disable return codes
+
+ili9881c_enable is always returning 0.
+
+ili9881c_disable was returning the error code from
+mipi_dsi_dcs_set_display_off.
+If non-zero, the drm_panel framework will leave the panel marked as
+enabled, and not run the enable hook next time around. That isn't
+helpful, particularly as we're expecting unprepare to disable
+resets and regulators.
+
+Change ili9881c_disable to match enable in always returning 0.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+@@ -1745,7 +1745,9 @@ static int ili9881c_disable(struct drm_p
+ {
+       struct ili9881c *ctx = panel_to_ili9881c(panel);
+-      return mipi_dsi_dcs_set_display_off(ctx->dsi);
++      mipi_dsi_dcs_set_display_off(ctx->dsi);
++
++      return 0;
+ }
+ static int ili9881c_unprepare(struct drm_panel *panel)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch b/target/linux/bcm27xx/patches-6.6/950-1263-dtoverlays-adds-the-definitions-for-the-HiFiBerry-8-.patch
new file mode 100644 (file)
index 0000000..0dff678
--- /dev/null
@@ -0,0 +1,113 @@
+From 77773aec03f65758c760ec5b43a79ad6edeb211b Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+Date: Thu, 12 Sep 2024 16:44:12 +0200
+Subject: [PATCH 1263/1350] dtoverlays: adds the definitions for the HiFiBerry
+ 8-channel ADC
+
+Additions and changes for the 8 channel ADC card. This card uses only
+HW-controlled devices which allows the uses of the 'dummy-dai'.
+It will run only on a PI5 as it requires the designware I2S0 module.
+
+The necessary output lanes I2S0_DI[0..3] are claimed from within the
+DT overlay.
+
+Signed-off-by: j-schambacher <joerg@hifiberry.com>
+---
+ arch/arm/boot/dts/overlays/Makefile           |  1 +
+ arch/arm/boot/dts/overlays/README             |  6 +++
+ .../dts/overlays/hifiberry-adc8x-overlay.dts  | 50 +++++++++++++++++++
+ arch/arm/boot/dts/overlays/overlay_map.dts    |  4 ++
+ 4 files changed, 61 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-adc8x-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       hd44780-lcd.dtbo \
+       hdmi-backlight-hwhack-gpio.dtbo \
+       hifiberry-adc.dtbo \
++      hifiberry-adc8x.dtbo \
+       hifiberry-amp.dtbo \
+       hifiberry-amp100.dtbo \
+       hifiberry-amp3.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1778,6 +1778,12 @@ Params: leds_off                If set t
+                                 is switched off at all times.
++Name:   hifiberry-adc8x
++Info:   Configures the HifiBerry ADC8X audio card (only on Pi5)
++Load:   dtoverlay=hifiberry-adc8x
++Params: <None>
++
++
+ Name:   hifiberry-amp
+ Info:   Configures the HifiBerry Amp and Amp+ audio cards
+ Load:   dtoverlay=hifiberry-amp
+--- /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";
++              };
++      };
++
++};
+--- a/arch/arm/boot/dts/overlays/overlay_map.dts
++++ b/arch/arm/boot/dts/overlays/overlay_map.dts
+@@ -48,6 +48,10 @@
+               bcm2712;
+       };
++      hifiberry-adc8x {
++              bcm2712;
++      };
++
+       hifiberry-dac8x {
+               bcm2712;
+       };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch b/target/linux/bcm27xx/patches-6.6/950-1264-ASoC-add-HiFiBerry-ADC8x-8-channel-ADC-to-simple-car.patch
new file mode 100644 (file)
index 0000000..87d523e
--- /dev/null
@@ -0,0 +1,88 @@
+From 4d2eaa194d77588fa42567ba174c3c14c5798027 Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+Date: Thu, 12 Sep 2024 17:42:13 +0200
+Subject: [PATCH 1264/1350] ASoC: add HiFiBerry ADC8x 8-channel ADC to
+ simple-card-driver
+
+Definitions for the 8 channel ADC card. The card uses only
+HW-controlled devices which allows the uses of the 'dummy-dai'.
+It will run only on a PI5 as it requires the designware I2S0 module.
+
+The necessary output lanes I2S0_DI[0..3] are claimed from within the
+DT overlay.
+
+Signed-off-by: j-schambacher <joerg@hifiberry.com>
+---
+ sound/soc/bcm/Kconfig                |  7 ++++++
+ sound/soc/bcm/rpi-simple-soundcard.c | 37 ++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+)
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -47,6 +47,13 @@ config SND_BCM2708_SOC_HIFIBERRY_ADC
+          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
+--- a/sound/soc/bcm/rpi-simple-soundcard.c
++++ b/sound/soc/bcm/rpi-simple-soundcard.c
+@@ -254,6 +254,41 @@ static struct snd_rpi_simple_drvdata drv
+       .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")),
+@@ -445,6 +480,8 @@ static const struct of_device_id snd_rpi
+               .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",
diff --git a/target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch b/target/linux/bcm27xx/patches-6.6/950-1265-vc04_services-codec-Allocate-the-max-number-of-buffe.patch
new file mode 100644 (file)
index 0000000..aa4c759
--- /dev/null
@@ -0,0 +1,35 @@
+From 8c9ca647449ba9df7e3b300c480242f9b5bdd867 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 10 Sep 2024 16:58:56 +0100
+Subject: [PATCH 1265/1350] vc04_services: codec: Allocate the max number of
+ buffers on the VPU
+
+The VPU's API can't match the use of VIDIOC_CREATE_BUFS to add buffers
+to the internal pool whilst a port is enabled, therefore allocate
+the maximum number of buffers possible in V4L2 to avoid the issue.
+As these are only buffer headers, the overhead is relatively small.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c   | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2871,8 +2871,14 @@ static int bcm2835_codec_queue_setup(str
+       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;
+ }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch b/target/linux/bcm27xx/patches-6.6/950-1266-drm-vc4-Fix-interpolate-bit-for-nearest-neighbour-fi.patch
new file mode 100644 (file)
index 0000000..7fd30b6
--- /dev/null
@@ -0,0 +1,26 @@
+From c1321370c9af9681e0604c4d3363cf362fb48598 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 16 Sep 2024 15:56:51 +0100
+Subject: [PATCH 1266/1350] drm: vc4: Fix interpolate bit for nearest neighbour
+ filter
+
+Operator precedence resulted in the wrong value being written
+for nearest neighbour mode. Correct it.
+
+Fixes: d6a3a3f10601 ("drm/vc4: Add support for per plane scaling filter selection")
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -623,7 +623,7 @@ static void vc4_write_ppf(struct vc4_pla
+       phase &= SCALER_PPF_IPHASE_MASK;
+       vc4_dlist_write(vc4_state,
+-                      no_interpolate ? SCALER_PPF_NOINTERP : 0 |
++                      (no_interpolate ? SCALER_PPF_NOINTERP : 0) |
+                       SCALER_PPF_AGC |
+                       VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
+                       /*
diff --git a/target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch b/target/linux/bcm27xx/patches-6.6/950-1267-dts-rp1-Disable-DMA-usage-for-UART0.patch
new file mode 100644 (file)
index 0000000..c809c4f
--- /dev/null
@@ -0,0 +1,34 @@
+From cc63d552b9aab92fb581dfb08267d5af697f477b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 18 Sep 2024 16:45:24 +0100
+Subject: [PATCH 1267/1350] dts: rp1: Disable DMA usage for UART0
+
+Some recent DMA changes have led to data loss in UART0 on Pi 5. It also
+seems that even prior to these changes there was a problem with aborted
+transfers.
+
+As this is the only RP1 UART configured for DMA, it is better to remove
+the DMA usage until it is shown to be reliable.
+
+Link: https://github.com/raspberrypi/linux/issues/6365
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/rp1.dtsi | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
+@@ -55,9 +55,9 @@
+                       interrupts = <RP1_INT_UART0 IRQ_TYPE_LEVEL_HIGH>;
+                       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";
++                      // 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;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch b/target/linux/bcm27xx/patches-6.6/950-1269-drivers-media-imx500-Fixes-for-vblank-control.patch
new file mode 100644 (file)
index 0000000..9b47eed
--- /dev/null
@@ -0,0 +1,50 @@
+From f6c0447dfb915538a0d5fa966fc26ca022cf49c8 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Fri, 20 Sep 2024 08:25:58 +0100
+Subject: [PATCH 1269/1350] drivers: media: imx500: Fixes for vblank control
+
+Reduce the default/max framerate of the 2x2 binned mode to 30fps.
+The current limit of 50fps can cause the sensor to produce corrupt
+frames and cause missing framing events.
+
+Also fixup the vblank control min/max/default/step paramters when
+setting up.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/imx500.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/i2c/imx500.c
++++ b/drivers/media/i2c/imx500.c
+@@ -47,7 +47,7 @@
+ /* V_TIMING internal */
+ #define IMX500_REG_FRAME_LENGTH CCI_REG16(0x0340)
+ #define IMX500_FRAME_LENGTH_MAX 0xffdc
+-#define IMX500_VBLANK_MIN 4
++#define IMX500_VBLANK_MIN 1117
+ /* H_TIMING internal */
+ #define IMX500_REG_LINE_LENGTH CCI_REG16(0x0342)
+@@ -922,7 +922,7 @@ static const struct imx500_mode imx500_s
+                       .width = 4056,
+                       .height = 3040,
+               },
+-              .framerate_default = 40,
++              .framerate_default = 30,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs),
+                       .regs = mode_2028x1520_regs,
+@@ -1771,10 +1771,10 @@ static void imx500_set_framing_limits(st
+       /* Update limits and set FPS to default */
+       __v4l2_ctrl_modify_range(
+-              imx500->vblank, 1,
++              imx500->vblank, IMX500_VBLANK_MIN,
+               ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) -
+                       mode->height,
+-              IMX500_VBLANK_MIN, frm_length_default - mode->height);
++              1, frm_length_default - mode->height);
+       /* Setting this will adjust the exposure limits as well. */
+       __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch b/target/linux/bcm27xx/patches-6.6/950-1270-drm-bridge-Document-bridge-init-order-with-pre_enabl.patch
new file mode 100644 (file)
index 0000000..14f9dd8
--- /dev/null
@@ -0,0 +1,56 @@
+From d62184f6b06627b4fe922b08132e38c181d389a0 Mon Sep 17 00:00:00 2001
+From: Jagan Teki <jagan@amarulasolutions.com>
+Date: Tue, 28 Mar 2023 22:37:52 +0530
+Subject: [PATCH 1270/1350] drm/bridge: Document bridge init order with
+ pre_enable_prev_first
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Upstream commit 113cc3ad8566e06d6c8ef4fc0075a938dedefab5
+
+In order to satisfy the MIPI DSI initialization sequence the bridge
+init order has been altered with the help of pre_enable_prev_first
+in pre_enable and post_disable bridge operations.
+
+Document the affected bridge init order with an example on the
+bridge operations helpers.
+
+Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
+Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Signed-off-by: Robert Foss <rfoss@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230328170752.1102347-2-jagan@amarulasolutions.com
+---
+ drivers/gpu/drm/drm_bridge.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- 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_
+  * 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_e
+  * 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/target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch b/target/linux/bcm27xx/patches-6.6/950-1271-drm-vc4-dsi-Don-t-reset-the-host-until-post_disable.patch
new file mode 100644 (file)
index 0000000..11094eb
--- /dev/null
@@ -0,0 +1,50 @@
+From ef34d0100e0f2f137ad0e6af333aad4e0d5c3319 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Thu, 2 May 2024 12:03:58 +0100
+Subject: [PATCH 1271/1350] drm/vc4: dsi: Don't reset the host until
+ post_disable
+
+Some DSI peripheral drivers wish to send commands in the
+post_disable or panel unprepare callback. These are called
+after the DSI host's disable call, but before the host's
+post_disable if pre_enable_prev_first is set.
+
+Don't reset the block until post_disable to allow these
+commands to be sent.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -818,6 +818,13 @@ static void vc4_dsi_bridge_disable(struc
+       disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
+       disp0_ctrl &= ~DSI_DISP0_ENABLE;
+       DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
++}
++
++static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
++                                      struct drm_bridge_state *state)
++{
++      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 |
+@@ -828,14 +835,6 @@ static void vc4_dsi_bridge_disable(struc
+                      DSI_PORT_BIT(PHY_AFEC0_PD) |
+                      DSI_PORT_BIT(AFEC0_PD_ALL_LANES));
+-}
+-
+-static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
+-                                      struct drm_bridge_state *state)
+-{
+-      struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+-      struct device *dev = &dsi->pdev->dev;
+-
+       clk_disable_unprepare(dsi->pll_phy_clock);
+       clk_disable_unprepare(dsi->escape_clock);
+       clk_disable_unprepare(dsi->pixel_clock);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch b/target/linux/bcm27xx/patches-6.6/950-1272-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch
new file mode 100644 (file)
index 0000000..e39e3b5
--- /dev/null
@@ -0,0 +1,111 @@
+From 6da70162dd1e729c04e2dc25472b39390868af79 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 20 Sep 2024 12:05:18 +0100
+Subject: [PATCH 1272/1350] drm: vc4: dsi: enable video and then retry failed
+ transfers
+
+The DSI block appears to be able to come up stuck in a condition where
+it leaves the lanes in HS mode or just jabbering. This stops LP
+transfers from completing as there is no LP time available. This is
+signalled via the LP1 contention error.
+
+Enabling video briefly clears that condition, so if we detect the
+error condition, enable video mode and then retry.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 54 +++++++++++++++++++++++++++++------
+ 1 file changed, 46 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -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
+@@ -1203,10 +1205,9 @@ static int vc4_dsi_bridge_attach(struct
+                                &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;
+@@ -1315,10 +1316,12 @@ static ssize_t vc4_dsi_host_transfer(str
+       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;
+@@ -1361,7 +1364,8 @@ static ssize_t vc4_dsi_host_transfer(str
+       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);
+@@ -1374,6 +1378,40 @@ reset_fifo_and_return:
+       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)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch b/target/linux/bcm27xx/patches-6.6/950-1273-drm-panel-ili9881-Add-option-to-reconfigure-setup-co.patch
new file mode 100644 (file)
index 0000000..1632925
--- /dev/null
@@ -0,0 +1,102 @@
+From d644270369cc6bf39012cce735dde6b86ad01424 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 18 Sep 2024 16:09:28 +0100
+Subject: [PATCH 1273/1350] drm: panel: ili9881: Add option to reconfigure
+ setup commands
+
+The driver is typically asking for LP commands, but then tries
+to send set_display_[on|off] from enable/disable when the host
+will be in HS mode.
+It also sends shutdown commands just before it asserts reset and
+disables the regulator, which is rather redundant.
+
+Add an option to configure these two choices from the panel_desc.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 32 ++++++++++++++++---
+ 1 file changed, 28 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+@@ -40,12 +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 {
+@@ -1727,6 +1734,12 @@ static int ili9881c_prepare(struct drm_p
+       if (ret)
+               return ret;
++      if (ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE) {
++              msleep(120);
++
++              ret = mipi_dsi_dcs_set_display_on(ctx->dsi);
++      }
++
+       return 0;
+ }
+@@ -1734,9 +1747,11 @@ static int ili9881c_enable(struct drm_pa
+ {
+       struct ili9881c *ctx = panel_to_ili9881c(panel);
+-      msleep(120);
++      if (!(ctx->desc->flags & ILI9881_FLAGS_PANEL_ON_IN_PREPARE)) {
++              msleep(120);
+-      mipi_dsi_dcs_set_display_on(ctx->dsi);
++              mipi_dsi_dcs_set_display_on(ctx->dsi);
++      }
+       return 0;
+ }
+@@ -1745,7 +1760,8 @@ static int ili9881c_disable(struct drm_p
+ {
+       struct ili9881c *ctx = panel_to_ili9881c(panel);
+-      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;
+ }
+@@ -1754,7 +1770,13 @@ static int ili9881c_unprepare(struct drm
+ {
+       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);
+@@ -2066,6 +2088,8 @@ static const struct ili9881c_desc rpi_7i
+       .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[] = {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch b/target/linux/bcm27xx/patches-6.6/950-1274-regulator-rpi-panel-Remove-the-ID-read.patch
new file mode 100644 (file)
index 0000000..8336b7a
--- /dev/null
@@ -0,0 +1,90 @@
+From b510e5cbbf8b8e2da3198cf931452290629876b7 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 20 Sep 2024 18:32:11 +0100
+Subject: [PATCH 1274/1350] regulator/rpi-panel: Remove the ID read
+
+Reading from the Atmel has always been troublesome due to
+clock stretching, and the driver does nothing with it anyway.
+
+Remove the read and assume that if the overlay has been
+configured (most likely through the firmware autodetection)
+that the hardware is present.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../regulator/rpi-panel-attiny-regulator.c    | 50 -------------------
+ 1 file changed, 50 deletions(-)
+
+--- a/drivers/regulator/rpi-panel-attiny-regulator.c
++++ b/drivers/regulator/rpi-panel-attiny-regulator.c
+@@ -229,39 +229,6 @@ static void attiny_gpio_set(struct gpio_
+       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
+  */
+@@ -273,7 +240,6 @@ static int attiny_i2c_probe(struct i2c_c
+       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);
+@@ -291,22 +257,6 @@ static int attiny_i2c_probe(struct i2c_c
+               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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch b/target/linux/bcm27xx/patches-6.6/950-1275-drivers-mfd-sensehat-Add-Raspberry-Pi-Sense-HAT-to-s.patch
new file mode 100644 (file)
index 0000000..f89dfa8
--- /dev/null
@@ -0,0 +1,29 @@
+From 2f9fad762e8ed78aa4220d582b4d1856808f4a7a Mon Sep 17 00:00:00 2001
+From: Charles Mirabile <cmirabil@redhat.com>
+Date: Tue, 19 Apr 2022 16:51:53 -0400
+Subject: [PATCH 1275/1350] drivers/mfd: sensehat: Add Raspberry Pi Sense HAT
+ to simple_mfd_i2c
+
+This patch adds the compatible string for the Sense HAT device to
+the list of compatible strings in the simple_mfd_i2c driver so that
+it can match against the device and load its children and their drivers
+
+Co-developed-by: Mwesigwa Guma <mguma@redhat.com>
+Signed-off-by: Mwesigwa Guma <mguma@redhat.com>
+Co-developed-by: Joel Savitz <jsavitz@redhat.com>
+Signed-off-by: Joel Savitz <jsavitz@redhat.com>
+Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
+---
+ drivers/mfd/simple-mfd-i2c.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mfd/simple-mfd-i2c.c
++++ b/drivers/mfd/simple-mfd-i2c.c
+@@ -98,6 +98,7 @@ static const struct of_device_id simple_
+       { .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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch b/target/linux/bcm27xx/patches-6.6/950-1281-dtoverlays-Correct-pinctrl-assignment-on-mcp23017.patch
new file mode 100644 (file)
index 0000000..ce0dd74
--- /dev/null
@@ -0,0 +1,24 @@
+From 78518a36d7c87bafdbb06478e6b54be5df4b355b Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 23 Sep 2024 17:49:00 +0100
+Subject: [PATCH 1281/1350] dtoverlays: Correct pinctrl assignment on mcp23017
+
+The pinctrl definition used "pinctrl-name" which is missing
+an "s" from the end.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -34,7 +34,7 @@
+               target = <&mcp23017>;
+               mcp23017_irq: __overlay__ {
+                       #interrupt-cells=<2>;
+-                      pinctrl-name = "default";
++                      pinctrl-names = "default";
+                       pinctrl-0 = <&mcp23017_pins>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = <4 2>;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch b/target/linux/bcm27xx/patches-6.6/950-1282-tty-serial-pl011-Also-unregister-pl011_axi_platform_.patch
new file mode 100644 (file)
index 0000000..3a5f9f1
--- /dev/null
@@ -0,0 +1,22 @@
+From 0fb3c83a9fa3011cb735ec011b7582d4749957b2 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Fri, 20 Sep 2024 12:21:27 +0100
+Subject: [PATCH 1282/1350] tty/serial: pl011: Also unregister
+ pl011_axi_platform_driver
+
+See: https://github.com/raspberrypi/linux/issues/6379
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ drivers/tty/serial/amba-pl011.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -3122,6 +3122,7 @@ static int __init pl011_init(void)
+ 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/target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch b/target/linux/bcm27xx/patches-6.6/950-1283-overlays-wm8960-soundcard-Fix-clock-declaration.patch
new file mode 100644 (file)
index 0000000..7a64d15
--- /dev/null
@@ -0,0 +1,62 @@
+From 409a0e2fd41da7a4b04672136aa7d749988faf61 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 25 Sep 2024 16:41:55 +0100
+Subject: [PATCH 1283/1350] overlays: wm8960-soundcard: Fix clock declaration
+
+How did this ever work? The static-clock declaration is fine, but the
+reference to it is attached to part of the simple-audio-card node,
+rather than the instantiation of the codec driver (a subnode of the
+I2C controller).
+
+Move the clock reference where it should be, and fix a few minor
+cosmetic issues at the same time.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ .../arm/boot/dts/overlays/wm8960-soundcard-overlay.dts | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts
++++ b/arch/arm/boot/dts/overlays/wm8960-soundcard-overlay.dts
+@@ -13,7 +13,7 @@
+       };
+       fragment@1 {
+-              target-path="/";
++              target-path = "/";
+               __overlay__ {
+                       wm8960_mclk: wm8960_mclk {
+                               compatible = "fixed-clock";
+@@ -29,17 +29,18 @@
+                       #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__ {
+@@ -67,10 +68,9 @@
+                       simple-audio-card,cpu {
+                               sound-dai = <&i2s_clk_producer>;
+                       };
++
+                       dailink0_slave: simple-audio-card,codec {
+                               sound-dai = <&wm8960>;
+-                              clocks = <&wm8960_mclk>;
+-                              clock-names = "mclk";
+                       };
+               };
+       };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch b/target/linux/bcm27xx/patches-6.6/950-1284-googlevoicehat-Fix-playback-muting-when-recording-is.patch
new file mode 100644 (file)
index 0000000..3ecccd6
--- /dev/null
@@ -0,0 +1,44 @@
+From d52d2bd85ad4d1cfc37a87a6b7bfcc37207c6025 Mon Sep 17 00:00:00 2001
+From: Ali Tekin <140681099+alitekin-saha@users.noreply.github.com>
+Date: Thu, 26 Sep 2024 10:51:13 +0300
+Subject: [PATCH 1284/1350] googlevoicehat: Fix playback muting when recording
+ is stopped
+
+Fixed audio amplifier control logic in the voicehat trigger function
+Resolves improper handling of the SDMODE pin, which caused issues when the microphone and speaker were used simultaneously. The playback stream check is now correctly based on `substream->stream == SNDRV_PCM_STREAM_PLAYBACK`, ensuring proper control of the audio amplifier.
+
+Signed-off-by: Ali Tekin <ali.tekin@saharobotik.com>
+---
+ sound/soc/bcm/googlevoicehat-codec.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/sound/soc/bcm/googlevoicehat-codec.c
++++ b/sound/soc/bcm/googlevoicehat-codec.c
+@@ -95,8 +95,7 @@ static int voicehat_daiops_trigger(struc
+                                  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;
+@@ -109,7 +108,7 @@ static int voicehat_daiops_trigger(struc
+       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,
+@@ -120,7 +119,7 @@ static int voicehat_daiops_trigger(struc
+       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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch b/target/linux/bcm27xx/patches-6.6/950-1285-ASoC-bcm2835-i2s-Set-the-PERIOD_BYTES-min-to-256.patch
new file mode 100644 (file)
index 0000000..5f148f4
--- /dev/null
@@ -0,0 +1,48 @@
+From a382d82b99a078f2ce65e78df9ba6db0d01c8ca3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 24 Sep 2024 20:34:54 +0100
+Subject: [PATCH 1285/1350] ASoC: bcm2835-i2s: Set the PERIOD_BYTES min to 256
+
+Commit [1] set the minimum PERIOD_BYTES value to the product of the DMA
+burst size and 8. For the I2S interface on BCM2835 that equates to 16
+where it used to be 256. ffmpeg uses the minimum value as its preferred
+value, leading to many, many very small periods, which affects
+performance and leads to complaints about DTS timestamps.
+
+Restore the previous behaviour and performance by making the bcm2835-i2s
+driver set a minimum PERIOD_BYTES value of 256.
+
+Link: https://github.com/raspberrypi/linux/issues/5709
+
+[1] 300689fb04b3 ("ASoC: soc-generic-dmaengine-pcm: set
+period_bytes_min based on maxburst")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -619,6 +619,10 @@ static int bcm2835_i2s_prepare(struct sn
+       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
+@@ -700,6 +704,10 @@ static int bcm2835_i2s_startup(struct sn
+       /* 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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch b/target/linux/bcm27xx/patches-6.6/950-1286-clk-clk-rp1-Don-t-crash-on-duplicate-clocks.patch
new file mode 100644 (file)
index 0000000..88a8774
--- /dev/null
@@ -0,0 +1,30 @@
+From d290bef1f99e24cd590c64db149d007c6a631b65 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 16 Sep 2024 11:48:08 +0100
+Subject: [PATCH 1286/1350] clk: clk-rp1: Don't crash on duplicate clocks
+
+When using DTBs that don't match the kernel version, it's possible for
+clock registration to fail. Handle that failure, in the hope that the
+system can continue to boot, with a suitable error message.
+
+Link: https://github.com/raspberrypi/linux/issues/6321
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/clk/clk-rp1.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/clk/clk-rp1.c
++++ b/drivers/clk/clk-rp1.c
+@@ -2454,6 +2454,11 @@ static int rp1_clk_probe(struct platform
+               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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch b/target/linux/bcm27xx/patches-6.6/950-1287-drivers-media-imx500-Simplify-the-vblank-control-ini.patch
new file mode 100644 (file)
index 0000000..b4bb7d8
--- /dev/null
@@ -0,0 +1,98 @@
+From 0094eba3f2a4338cfa6854b0b5104d02ba0fa01f Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Thu, 26 Sep 2024 13:12:23 +0100
+Subject: [PATCH 1287/1350] drivers: media: imx500: Simplify the vblank control
+ init
+
+Set the VBLANK control minimum and default values to IMX500_VBLANK_MIN
+unconditionally everywhere.
+
+Remove the mode specific framerate_default parameter, it is now unused.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/imx500.c | 32 +++++---------------------------
+ 1 file changed, 5 insertions(+), 27 deletions(-)
+
+--- a/drivers/media/i2c/imx500.c
++++ b/drivers/media/i2c/imx500.c
+@@ -274,9 +274,6 @@ struct imx500_mode {
+       /* Analog crop rectangle. */
+       struct v4l2_rect crop;
+-      /* Default framerate. */
+-      unsigned int framerate_default;
+-
+       /* Default register values */
+       struct imx500_reg_list reg_list;
+ };
+@@ -905,7 +902,6 @@ static const struct imx500_mode imx500_s
+                       .width = 4056,
+                       .height = 3040,
+               },
+-              .framerate_default = 10,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs),
+                       .regs = mode_4056x3040_regs,
+@@ -922,7 +918,6 @@ static const struct imx500_mode imx500_s
+                       .width = 4056,
+                       .height = 3040,
+               },
+-              .framerate_default = 30,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_2028x1520_regs),
+                       .regs = mode_2028x1520_regs,
+@@ -1744,28 +1739,11 @@ static int imx500_get_pad_format(struct
+       return 0;
+ }
+-static unsigned int imx500_get_frame_length(const struct imx500_mode *mode,
+-                                          unsigned int framerate_default)
+-{
+-      u64 frame_length;
+-
+-      frame_length = IMX500_PIXEL_RATE;
+-      do_div(frame_length, (u64)framerate_default * mode->line_length_pix);
+-
+-      if (WARN_ON(frame_length > IMX500_FRAME_LENGTH_MAX))
+-              frame_length = IMX500_FRAME_LENGTH_MAX;
+-
+-      return max_t(unsigned int, frame_length, mode->height);
+-}
+-
+ static void imx500_set_framing_limits(struct imx500 *imx500)
+ {
+-      unsigned int frm_length_default, hblank_min;
++      unsigned int hblank_min;
+       const struct imx500_mode *mode = imx500->mode;
+-      frm_length_default =
+-              imx500_get_frame_length(mode, mode->framerate_default);
+-
+       /* Default to no long exposure multiplier. */
+       imx500->long_exp_shift = 0;
+@@ -1773,11 +1751,10 @@ static void imx500_set_framing_limits(st
+       __v4l2_ctrl_modify_range(
+               imx500->vblank, IMX500_VBLANK_MIN,
+               ((1 << IMX500_LONG_EXP_SHIFT_MAX) * IMX500_FRAME_LENGTH_MAX) -
+-                      mode->height,
+-              1, frm_length_default - mode->height);
++                      mode->height, 1, IMX500_VBLANK_MIN);
+       /* Setting this will adjust the exposure limits as well. */
+-      __v4l2_ctrl_s_ctrl(imx500->vblank, frm_length_default - mode->height);
++      __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,
+@@ -2499,7 +2476,8 @@ static int imx500_init_controls(struct i
+        * in the imx500_set_framing_limits() call below.
+        */
+       imx500->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx500_ctrl_ops,
+-                                         V4L2_CID_VBLANK, 0, 0xffff, 1, 0);
++                                         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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1288-dts-overlay_map-ramoops-pi4-works-on-Pi-5.patch
new file mode 100644 (file)
index 0000000..43011ba
--- /dev/null
@@ -0,0 +1,28 @@
+From 9557336c4fc4ac4606ac9e78c239aa689c26e870 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 26 Sep 2024 17:46:25 +0100
+Subject: [PATCH 1288/1350] dts: overlay_map: ramoops-pi4 works on Pi 5
+
+Add the necessary overlay_map entries so that ramoops-pi4 is loaded
+with dtoverlay=ramoops on Pi 5.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/overlay_map.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/overlay_map.dts
++++ b/arch/arm/boot/dts/overlays/overlay_map.dts
+@@ -247,10 +247,12 @@
+       ramoops {
+               bcm2835;
+               bcm2711 = "ramoops-pi4";
++              bcm2712 = "ramoops-pi4";
+       };
+       ramoops-pi4 {
+               bcm2711;
++              bcm2712;
+       };
+       rpi-cirrus-wm5102 {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch b/target/linux/bcm27xx/patches-6.6/950-1289-dts-align-PCI-BAR-allocation-on-bcm2711-and-bcm2712-.patch
new file mode 100644 (file)
index 0000000..c54f221
--- /dev/null
@@ -0,0 +1,109 @@
+From 2b5de12af9bb390239d5f3385c49e0c34f335de8 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 27 Sep 2024 10:59:02 +0100
+Subject: [PATCH 1289/1350] dts: align PCI BAR allocation on bcm2711 and
+ bcm2712 to start at 2GB
+
+Fold the Pi 5 mmio-hi compatibility option into the base DTB, and
+shuffle the single MMIO window on bcm2711 to match.
+
+Certain devices cannot handle low addresses, e.g. by failing to
+enumerate or failing to route the traffic appropriately.
+
+Link: https://github.com/raspberrypi/linux/issues/6134
+Link: https://github.com/raspberrypi/linux/issues/6278
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ .../arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi |  6 +++---
+ arch/arm/boot/dts/overlays/README             |  2 --
+ .../overlays/pciex1-compat-pi5-overlay.dts    | 20 -------------------
+ arch/arm64/boot/dts/broadcom/bcm2712.dtsi     | 10 ++++++----
+ 4 files changed, 9 insertions(+), 29 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
+@@ -123,7 +123,7 @@
+       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>;
+@@ -167,8 +167,8 @@
+ &pcie0 {
+       reg = <0x0 0x7d500000  0x0 0x9310>;
+-      ranges = <0x02000000 0x0 0xc0000000 0x6 0x00000000
+-                0x0 0x40000000>;
++      ranges = <0x02000000 0x0 0x80000000 0x6 0x00000000
++                0x0 0x80000000>;
+ };
+ &genet {
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -3617,8 +3617,6 @@ Params: l1ss                    Enable A
+                                 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.
+-        mmio-hi                 Move the start of outbound 32bit addresses to
+-                                2GB and expand 64bit outbound space to 14GB.
+ [ The pcf2127-rtc overlay has been deleted. See i2c-rtc. ]
+--- a/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pciex1-compat-pi5-overlay.dts
+@@ -32,29 +32,9 @@
+               };
+       };
+-      /*
+-       * Shift the start of the 32bit outbound window to 2GB,
+-       * so there are no BARs starting at 0x0. Expand the 64bit
+-       * outbound window to use the spare 2GB.
+-       */
+-      fragment@3 {
+-              target = <&pciex1>;
+-              __dormant__ {
+-                      #address-cells = <3>;
+-                      #size-cells = <2>;
+-                      ranges = <0x02000000 0x00 0x80000000
+-                                0x1b 0x80000000
+-                                0x00 0x7ffffffc>,
+-                               <0x43000000 0x04 0x00000000
+-                                0x18 0x00000000
+-                                0x03 0x80000000>;
+-              };
+-      };
+-
+       __overrides__ {
+               l1ss = <0>, "+0";
+               no-l0s = <0>, "+1";
+               no-mip = <0>, "+2";
+-              mmio-hi = <0>, "+3";
+       };
+ };
+--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+@@ -1052,12 +1052,14 @@
+                       msi-controller;
+                       msi-parent = <&mip1>;
+-                      ranges = <0x02000000 0x00 0x00000000
+-                                0x1b 0x00000000
+-                                0x00 0xfffffffc>,
++                      // 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 0x00000000>;
++                                0x03 0x80000000>;
+                       dma-ranges = <0x03000000 0x10 0x00000000
+                                     0x00 0x00000000
diff --git a/target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch b/target/linux/bcm27xx/patches-6.6/950-1290-overlays-Add-Pineboards-HatDrive-POE-6257.patch
new file mode 100644 (file)
index 0000000..583602d
--- /dev/null
@@ -0,0 +1,61 @@
+From 35b3f98bb2bfb80a718c52ba49c167da6c78d2ea Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micha=C5=82=20Gapi=C5=84ski?=
+ <mikegapinski@users.noreply.github.com>
+Date: Mon, 30 Sep 2024 16:47:20 +0200
+Subject: [PATCH 1290/1350] overlays: Add Pineboards HatDrive! POE+ (#6257)
+
+overlays: Add Pineboards HatDrive! POE+
+---
+ arch/arm/boot/dts/overlays/Makefile           |  1 +
+ arch/arm/boot/dts/overlays/README             |  6 ++++++
+ .../pineboards-hatdrive-poe-plus-overlay.dts  | 19 +++++++++++++++++++
+ 3 files changed, 26 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/pineboards-hatdrive-poe-plus-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -204,6 +204,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       pifi-mini-210.dtbo \
+       piglow.dtbo \
+       pineboards-hat-ai.dtbo \
++      pineboards-hatdrive-poe-plus.dtbo \
+       piscreen.dtbo \
+       piscreen2r.dtbo \
+       pisound.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -3703,6 +3703,12 @@ Load:   dtoverlay=pineboards-hat-ai
+ Params: <None>
++Name:   pineboards-hatdrive-poe-plus
++Info:   Configures the Pineboards HatDrive! PoE+
++Load:   dtoverlay=pineboards-hatdrive-poe-plus
++Params: <None>
++
++
+ Name:   piscreen
+ Info:   PiScreen display by OzzMaker.com
+ Load:   dtoverlay=piscreen,<param>=<val>
+--- /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/target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch b/target/linux/bcm27xx/patches-6.6/950-1296-dtoverlays-Correct-vc4-kms-dpi-generic-for-width-hei.patch
new file mode 100644 (file)
index 0000000..f56147c
--- /dev/null
@@ -0,0 +1,31 @@
+From 50a6e5cf28a24e7f4192ad6f70f472eca2097cc6 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 2 Oct 2024 16:36:45 +0100
+Subject: [PATCH 1296/1350] dtoverlays: Correct vc4-kms-dpi-generic for
+ [width|height]-mm
+
+These two overrides were updating the &panel node from
+vc4-kms-dpi.dtsi, when fragment0 from the vc4-kms-dpi-generic
+was also updating the same node. Application order meant that
+the override value was overwritten.
+
+Correct the target.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts
+@@ -60,8 +60,8 @@
+               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>;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch b/target/linux/bcm27xx/patches-6.6/950-1297-dts-bcm2712-rpi-Add-four-missing-GPIOs-to-2712D0.patch
new file mode 100644 (file)
index 0000000..2ccd898
--- /dev/null
@@ -0,0 +1,32 @@
+From e044f6af1b2b41bc2212551b4fd6353469cb7263 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 12 Sep 2024 16:29:57 +0100
+Subject: [PATCH 1297/1350] dts: bcm2712-rpi: Add four missing GPIOs to 2712D0
+
+It's useful for gpioinfo and pinctrl to distinguish between unused and
+absent GPIOs. We use "-" for the former and "" for the latter.
+With this convention, gpioinfo shows absent GPIOs as "unnamed", while
+pinctrl omits them altogether.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
+@@ -15,10 +15,10 @@
+               "", // GPIO_007
+               "", // GPIO_008
+               "", // GPIO_009
+-              "", // GPIO_010
+-              "", // GPIO_011
+-              "", // GPIO_012
+-              "", // GPIO_013
++              "-", // GPIO_010
++              "-", // GPIO_011
++              "-", // GPIO_012
++              "-", // GPIO_013
+               "PCIE_SDA", // GPIO_014
+               "PCIE_SCL", // GPIO_015
+               "", // GPIO_016
diff --git a/target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch b/target/linux/bcm27xx/patches-6.6/950-1298-arm64-dts-Add-preliminary-bcm2712-rpi-500-dts.patch
new file mode 100644 (file)
index 0000000..6d961a7
--- /dev/null
@@ -0,0 +1,169 @@
+From 3be1a52ad9e3ae7b0e16eb20c77d9df60e29f139 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 10 Sep 2024 14:07:16 +0100
+Subject: [PATCH 1298/1350] arm64: dts: Add preliminary bcm2712-rpi-500 dts
+
+Add the first DTS file for Pi 500.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/Makefile         |   1 +
+ .../boot/dts/broadcom/bcm2712-rpi-500.dts     | 142 ++++++++++++++++++
+ 2 files changed, 143 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
+
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -22,6 +22,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rp
+ 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
+--- /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
++              "-", // 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/target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch b/target/linux/bcm27xx/patches-6.6/950-1301-dts-2712-Reduce-default-cma-usage-on-Pi5.patch
new file mode 100644 (file)
index 0000000..bb26a89
--- /dev/null
@@ -0,0 +1,30 @@
+From 3edaa3875fbeb0b2effd77c62baabf2933efc6ef Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Fri, 13 Sep 2024 17:23:58 +0100
+Subject: [PATCH 1301/1350] dts: 2712: Reduce default cma usage on Pi5
+
+Significant cma shouldn't really be needed on Pi5 as the hardware
+blocks support iommu and can access system memory.
+
+We've migrated codec and camera support to system memory, and 3d
+has always (even on Pi4) used system memory.
+
+A large cma block causes issues with enabling NUMA on a low
+memory (2G) Pi5, as cma cannot span numa regions.
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi5-overlay.dts
+@@ -3,7 +3,7 @@
+ #include "cma-overlay.dts"
+ &frag0 {
+-      size = <((320-4)*1024*1024)>;
++      size = <(64*1024*1024)>;
+ };
+ / {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch b/target/linux/bcm27xx/patches-6.6/950-1305-dts-bcm2712d0-Add-non-d0-vc6-compatible-string.patch
new file mode 100644 (file)
index 0000000..4660c8f
--- /dev/null
@@ -0,0 +1,39 @@
+From d69bca1f0425be1a42f7ad1e3cff5313ba7c122a Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 9 Oct 2024 15:13:14 +0100
+Subject: [PATCH 1305/1350] dts: bcm2712d0: Add non-d0 vc6 compatible string
+
+Although the VC4/VC6 driver requires a special compatible string for the
+"d0" stepping, the removal of the old compatible string upsets Mesa.
+
+Satisfy both requirements by adding the old "brcm,bcm2712-vc6" string
+as a fallback.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts   | 2 +-
+ arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/bcm2712d0-overlay.dts
+@@ -41,7 +41,7 @@
+       fragment@4 {
+               target = <&vc4>;
+               __overlay__ {
+-                      compatible = "brcm,bcm2712d0-vc6";
++                      compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6";
+               };
+       };
+--- a/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dts
+@@ -87,7 +87,7 @@
+ };
+ &vc4 {
+-      compatible = "brcm,bcm2712d0-vc6";
++      compatible = "brcm,bcm2712d0-vc6", "brcm,bcm2712-vc6";
+ };
+ &uart10 {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch b/target/linux/bcm27xx/patches-6.6/950-1312-Reapply-dtoverlays-Convert-SenseHAT-overlays-to-use-.patch
new file mode 100644 (file)
index 0000000..9501067
--- /dev/null
@@ -0,0 +1,100 @@
+From 9a86952570b925e68dfd30a12642000353242745 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Thu, 10 Oct 2024 17:16:08 +0100
+Subject: [PATCH 1312/1350] Reapply "dtoverlays: Convert SenseHAT overlays to
+ use MFD and upstream drivers"
+
+This reverts commit 82a50e430ef1d6eb37d78e25aa572c1f6ea56160.
+---
+ .../boot/dts/overlays/rpi-sense-overlay.dts   | 28 +++++++++++++++++--
+ .../dts/overlays/rpi-sense-v2-overlay.dts     | 28 +++++++++++++++++--
+ 2 files changed, 50 insertions(+), 6 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
+@@ -12,11 +12,23 @@
+                       #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 {
+@@ -44,4 +56,14 @@
+                       };
+               };
+       };
++
++      fragment@1 {
++              target = <&gpio>;
++              __overlay__ {
++                      sensehat_pins: sensehat_pins {
++                              brcm,pins = <23>;
++                              brcm,function = <0>;
++                      };
++              };
++      };
+ };
+--- a/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-sense-v2-overlay.dts
+@@ -12,11 +12,23 @@
+                       #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 {
+@@ -44,4 +56,14 @@
+                       };
+               };
+       };
++
++      fragment@1 {
++              target = <&gpio>;
++              __overlay__ {
++                      sensehat_pins: sensehat_pins {
++                              brcm,pins = <23>;
++                              brcm,function = <0>;
++                      };
++              };
++      };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch b/target/linux/bcm27xx/patches-6.6/950-1313-Reapply-drivers-Remove-downstream-SenseHAT-core-and-.patch
new file mode 100644 (file)
index 0000000..714123d
--- /dev/null
@@ -0,0 +1,608 @@
+From 9fb57f6b8920a8aceb74ceb3e171a7e5769205a5 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Thu, 10 Oct 2024 17:18:39 +0100
+Subject: [PATCH 1313/1350] Reapply "drivers: Remove downstream SenseHAT core
+ and joystick drivers"
+
+This reverts commit e6493e2d6a1f572fbb4a1d724e54715cb748b424.
+---
+ drivers/input/joystick/Kconfig           |   8 --
+ drivers/input/joystick/Makefile          |   1 -
+ drivers/input/joystick/rpisense-js.c     | 153 ---------------------
+ drivers/mfd/Kconfig                      |   8 --
+ drivers/mfd/Makefile                     |   1 -
+ drivers/mfd/rpisense-core.c              | 163 -----------------------
+ drivers/video/fbdev/Kconfig              |   4 +-
+ drivers/video/fbdev/rpisense-fb.c        |  53 ++++----
+ include/linux/mfd/rpisense/core.h        |  47 -------
+ include/linux/mfd/rpisense/framebuffer.h |   5 +-
+ 10 files changed, 32 insertions(+), 411 deletions(-)
+ delete mode 100644 drivers/input/joystick/rpisense-js.c
+ delete mode 100644 drivers/mfd/rpisense-core.c
+ delete mode 100644 include/linux/mfd/rpisense/core.h
+
+--- a/drivers/input/joystick/Kconfig
++++ b/drivers/input/joystick/Kconfig
+@@ -412,12 +412,4 @@ config JOYSTICK_SENSEHAT
+         To compile this driver as a module, choose M here: the
+         module will be called sensehat_joystick.
+-config JOYSTICK_RPISENSE
+-      tristate "Raspberry Pi Sense HAT joystick"
+-      depends on GPIOLIB && INPUT
+-      select MFD_RPISENSE_CORE
+-
+-      help
+-        This is the joystick driver for the Raspberry Pi Sense HAT
+-
+ endif
+--- a/drivers/input/joystick/Makefile
++++ b/drivers/input/joystick/Makefile
+@@ -40,4 +40,3 @@ obj-$(CONFIG_JOYSTICK_WARRIOR)               += warri
+ 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
+--- a/drivers/input/joystick/rpisense-js.c
++++ /dev/null
+@@ -1,153 +0,0 @@
+-/*
+- * 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 <linux/module.h>
+-
+-#include <linux/mfd/rpisense/joystick.h>
+-#include <linux/mfd/rpisense/core.h>
+-
+-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 <serge@raspberrypi.org>");
+-MODULE_LICENSE("GPL");
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -11,14 +11,6 @@ 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
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -268,7 +268,6 @@ 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
+ obj-$(CONFIG_SGI_MFD_IOC3)    += ioc3.o
+ obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)      += simple-mfd-i2c.o
+--- a/drivers/mfd/rpisense-core.c
++++ /dev/null
+@@ -1,163 +0,0 @@
+-/*
+- * 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 <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/err.h>
+-#include <linux/init.h>
+-#include <linux/i2c.h>
+-#include <linux/platform_device.h>
+-#include <linux/mfd/rpisense/core.h>
+-#include <linux/slab.h>
+-
+-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 <serge@raspberrypi.org>");
+-MODULE_LICENSE("GPL");
+-
+--- a/drivers/video/fbdev/Kconfig
++++ b/drivers/video/fbdev/Kconfig
+@@ -1967,8 +1967,8 @@ config FB_SM712
+ 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
+--- a/drivers/video/fbdev/rpisense-fb.c
++++ b/drivers/video/fbdev/rpisense-fb.c
+@@ -23,16 +23,14 @@
+ #include <linux/delay.h>
+ #include <linux/fb.h>
+ #include <linux/init.h>
++#include <linux/platform_device.h>
+ #include <linux/mfd/rpisense/framebuffer.h>
+-#include <linux/mfd/rpisense/core.h>
+ 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;
+@@ -116,26 +114,26 @@ static void rpisense_fb_imageblit(struct
+ }
+ 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 = {
+@@ -200,8 +198,22 @@ static int rpisense_fb_probe(struct plat
+       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)
+@@ -211,12 +223,6 @@ static int rpisense_fb_probe(struct plat
+       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;
+@@ -253,7 +259,7 @@ err_malloc:
+ 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) {
+@@ -266,19 +272,11 @@ static int rpisense_fb_remove(struct pla
+       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,
+@@ -286,6 +284,7 @@ static struct platform_driver rpisense_f
+       .driver = {
+               .name = "rpi-sense-fb",
+               .owner = THIS_MODULE,
++              .of_match_table = rpisense_fb_id,
+       },
+ };
+--- a/include/linux/mfd/rpisense/core.h
++++ /dev/null
+@@ -1,47 +0,0 @@
+-/*
+- * 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 <linux/mfd/rpisense/joystick.h>
+-#include <linux/mfd/rpisense/framebuffer.h>
+-
+-/*
+- * 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
+--- a/include/linux/mfd/rpisense/framebuffer.h
++++ b/include/linux/mfd/rpisense/framebuffer.h
+@@ -16,6 +16,8 @@
+ #ifndef __LINUX_RPISENSE_FB_H_
+ #define __LINUX_RPISENSE_FB_H_
++#include <linux/regmap.h>
++
+ #define SENSEFB_FBIO_IOC_MAGIC 0xF1
+ #define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
+@@ -25,8 +27,9 @@
+ struct rpisense;
+ struct rpisense_fb {
+-      struct platform_device *pdev;
+       struct fb_info *info;
++      struct platform_device *pdev;
++      struct regmap *regmap;
+ };
+ #endif
diff --git a/target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch b/target/linux/bcm27xx/patches-6.6/950-1315-Reapply-Input-sensehat-joystick-Revert-to-downstream.patch
new file mode 100644 (file)
index 0000000..87d84a9
--- /dev/null
@@ -0,0 +1,22 @@
+From 3a7ab92b9be0f8849941ed66049b9c3744cbd5aa Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Thu, 10 Oct 2024 17:18:57 +0100
+Subject: [PATCH 1315/1350] Reapply "Input: sensehat-joystick : Revert to
+ downstream keymap"
+
+This reverts commit bdb00151ff537c119cea7125e665a9bee1f76c58.
+---
+ drivers/input/joystick/sensehat-joystick.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/input/joystick/sensehat-joystick.c
++++ b/drivers/input/joystick/sensehat-joystick.c
+@@ -28,7 +28,7 @@ struct sensehat_joystick {
+ };
+ 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/target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch b/target/linux/bcm27xx/patches-6.6/950-1316-Reapply-dtoverlays-Add-Sense-Hat-to-hat_map.patch
new file mode 100644 (file)
index 0000000..c4a2ee2
--- /dev/null
@@ -0,0 +1,27 @@
+From 2132f8aad4e978a9789a84f667567ce2bc93cb3c Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Thu, 10 Oct 2024 17:19:06 +0100
+Subject: [PATCH 1316/1350] Reapply "dtoverlays: Add Sense Hat to hat_map"
+
+This reverts commit 14fc8b7994220e9b3d85c07b53c5704d5e082944.
+---
+ arch/arm/boot/dts/overlays/hat_map.dts | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/hat_map.dts
++++ b/arch/arm/boot/dts/overlays/hat_map.dts
+@@ -95,4 +95,14 @@
+               uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ];
+               overlay = "recalboxrgbdual";
+       };
++
++      sensehat-v1 {
++              uuid = [ 5d960035 8e87 428f 95d8 59852d697754 ];
++              overlay = "rpi-sense";
++      };
++
++      sensehat-v2 {
++              uuid = [ 1aa9c428 72eb 48da 9306 8c3706ed3653 ];
++              overlay = "rpi-sense-v2";
++      };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch b/target/linux/bcm27xx/patches-6.6/950-1317-overlays-hat_map-Add-Sense-and-Hailo-AI-HATs.patch
new file mode 100644 (file)
index 0000000..041447e
--- /dev/null
@@ -0,0 +1,54 @@
+From e53eefbc711622f0702e887f88d69f867aa0bf1a Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 1 Oct 2024 12:14:57 +0100
+Subject: [PATCH 1317/1350] overlays: hat_map: Add Sense and Hailo AI HATs
+
+Add mappings to overlays for the Sense HATs and the Hailo AI HATs. Note
+that mapping by product names (and not UUIDs) as used here requires an
+updated firmware.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/hat_map.dts | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/hat_map.dts
++++ b/arch/arm/boot/dts/overlays/hat_map.dts
+@@ -1,6 +1,18 @@
+ /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";
+@@ -97,12 +109,16 @@
+       };
+       sensehat-v1 {
+-              uuid = [ 5d960035 8e87 428f 95d8 59852d697754 ];
++              product = "Sense HAT";
++              vendor = "Raspberry Pi";
++              pver = < 0x0001 >;
+               overlay = "rpi-sense";
+       };
+       sensehat-v2 {
+-              uuid = [ 1aa9c428 72eb 48da 9306 8c3706ed3653 ];
++              product = "Sense HAT";
++              vendor = "Raspberry Pi";
++              pver = < 0x0002 >;
+               overlay = "rpi-sense-v2";
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch b/target/linux/bcm27xx/patches-6.6/950-1318-drivers-media-imx500-Enable-LS-correction.patch
new file mode 100644 (file)
index 0000000..6d3233c
--- /dev/null
@@ -0,0 +1,408 @@
+From e2cafea49115af21f84e315e228121ec10dd4cb3 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Fri, 11 Oct 2024 12:32:46 +0100
+Subject: [PATCH 1318/1350] drivers: media: imx500: Enable LS correction
+
+This correction is calibrated to approx 5000K.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/imx500.c | 387 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 387 insertions(+)
+
+--- a/drivers/media/i2c/imx500.c
++++ b/drivers/media/i2c/imx500.c
+@@ -887,6 +887,393 @@ static const struct cci_reg_sequence dnn
+       { 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 */
diff --git a/target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch b/target/linux/bcm27xx/patches-6.6/950-1319-dts-bcm2712-rpi-500-Add-USER_LED-GPIO-name.patch
new file mode 100644 (file)
index 0000000..0dabf4b
--- /dev/null
@@ -0,0 +1,23 @@
+From 0985b32279d47e7ea01152233d26eedcdf721d09 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 11 Oct 2024 14:24:51 +0100
+Subject: [PATCH 1319/1350] dts: bcm2712-rpi-500: Add USER_LED GPIO name
+
+The USER_LED signal was missing from the initial DTS.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
+@@ -35,7 +35,7 @@
+               "PWR_GPIO", // GPIO_020
+               "KEYB_RUN", // GPIO_021
+               "-", // GPIO_022
+-              "-", // GPIO_023
++              "USER_LED", // GPIO_023
+               "BT_RTS", // GPIO_024
+               "BT_CTS", // GPIO_025
+               "BT_TXD", // GPIO_026
diff --git a/target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch b/target/linux/bcm27xx/patches-6.6/950-1321-dtoverlays-Fix-up-imx500-overlays-to-have-unique-clo.patch
new file mode 100644 (file)
index 0000000..b8e67c6
--- /dev/null
@@ -0,0 +1,86 @@
+From 239df148741e35d5b54749a624f96dfcacc7c57e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 14 Oct 2024 15:37:57 +0100
+Subject: [PATCH 1321/1350] dtoverlays: Fix up imx500 overlays to have unique
+ clock nodes
+
+The overlay was creating DT nodes /clocks/clk-aicam and
+/clocks/clk-aicam-gated for both cam0 and cam1, which resulted
+in one failing.
+
+The clock infrastructure creates the clock name from the node name
+without any @N reg extension, so we can't just use that. The nodes
+therefore have to be renamed.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/imx500-overlay.dts     | 10 ++++++----
+ arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts | 10 ++++++----
+ 2 files changed, 12 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/imx500-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx500-overlay.dts
+@@ -72,16 +72,16 @@
+               };
+       };
+-      clocks_frag: fragment@104 {
++      fragment@104 {
+               target-path = "/clocks";
+               __overlay__ {
+-                      clk_aicam: clk-aicam {
++                      clk_aicam: clk-aicam1 {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-frequency = <24000000>;
+                       };
+-                      clk_aicam_gated: clk-aicam-gated {
++                      clk_aicam_gated: clk-aicam-gated1 {
+                               compatible = "gpio-gate-clock";
+                               clocks = <&clk_aicam>;
+                               #clock-cells = <0>;
+@@ -98,7 +98,9 @@
+                      <&csi_frag>, "target:0=",<&csi0>,
+                          <&spi_bridge>, "power-supply:0=",<&cam0_reg>,
+                      <&reg_frag>, "target:0=",<&cam0_reg>,
+-                     <&cam_node>, "VANA-supply: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?";
+       };
+ };
+--- a/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx500-pi5-overlay.dts
+@@ -75,16 +75,16 @@
+               };
+       };
+-      clocks_frag: fragment@104 {
++      fragment@104 {
+               target-path = "/clocks";
+               __overlay__ {
+-                      clk_aicam: clk-aicam {
++                      clk_aicam: clk-aicam1 {
+                               compatible = "fixed-clock";
+                               #clock-cells = <0>;
+                               clock-frequency = <24000000>;
+                       };
+-                      clk_aicam_gated: clk-aicam-gated {
++                      clk_aicam_gated: clk-aicam-gated1 {
+                               compatible = "gpio-gate-clock";
+                               clocks = <&clk_aicam>;
+                               #clock-cells = <0>;
+@@ -103,7 +103,9 @@
+                          <&spi_frag_overlay>, "fast_xfer-gpios:16=35", // CD0_IO1_MICDAT0 (clock)
+                          <&spi_bridge>, "power-supply:0=",<&cam0_reg>,
+                      <&reg_frag>, "target:0=",<&cam0_reg>,
+-                     <&cam_node>, "VANA-supply: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?";
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch b/target/linux/bcm27xx/patches-6.6/950-1322-dtoverlays-Add-an-overlay-for-Waveshare-s-800x480-4..patch
new file mode 100644 (file)
index 0000000..4a66798
--- /dev/null
@@ -0,0 +1,177 @@
+From 6f2d1b4c3132206de40247b604638a51277131fb Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 14 Oct 2024 18:53:43 +0100
+Subject: [PATCH 1322/1350] dtoverlays: Add an overlay for Waveshare's 800x480
+ 4.3" DSI screen
+
+It tried to be a clone of the Pi 7" display, but isn't, and gives
+corrupt images with the current timings.
+
+Add a new overlay for it.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/Makefile           |   1 +
+ arch/arm/boot/dts/overlays/README             |  17 +++
+ .../vc4-kms-dsi-waveshare-800x480-overlay.dts | 119 ++++++++++++++++++
+ 3 files changed, 137 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -319,6 +319,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+       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 \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -5248,6 +5248,23 @@ Load:   dtoverlay=vc4-kms-dsi-lt070me050
+ Params: <None>
++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,<param>=<val>
++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.
+--- /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 = <&reg_display>;
++                              backlight = <&reg_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 = <&reg_display 0 0>;
++                              vin-supply = <&reg_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 = <&reg_display>;
++                      reset-gpio = <&reg_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>,
++                     <&reg_bridge>, "reg:0=0",
++                     <&reg_bridge>, "regulator-name=bridge_reg_0";
++              disable_touch = <&ft5406>, "status=disabled";
++      };
++};
diff --git a/target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch b/target/linux/bcm27xx/patches-6.6/950-1323-drm-vc4-Remove-request-for-min-clocks-when-hdmi-outp.patch
new file mode 100644 (file)
index 0000000..9f4cf9d
--- /dev/null
@@ -0,0 +1,74 @@
+From 18d185166ca00c9280505ad41fbe036efbb52e67 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Mon, 14 Oct 2024 18:55:00 +0100
+Subject: [PATCH 1323/1350] drm/vc4: Remove request for min clocks when hdmi
+ output is disabled
+
+Currently, booting with no hdmi connected has:
+pi@pi4:~ $ vcgencmd measure_clock hdmi pixel
+frequency(9)=120010256
+frequency(29)=74988280
+
+After connecting hdmi we get:
+pi@pi4:~ $ vcgencmd measure_clock hdmi pixel
+frequency(9)=300005856
+frequency(29)=149989744
+
+and that persists after disconnecting hdmi
+
+I can measure this on a power supply as 10mA@5.2V (52mW).
+
+We should always remove clk_set_min_rate requests
+when we no longer need them.
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++
+ drivers/gpu/drm/vc4/vc4_hvs.c  | 3 +++
+ drivers/gpu/drm/vc4/vc4_v3d.c  | 2 ++
+ 3 files changed, 9 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -1224,6 +1224,8 @@ static void vc4_hdmi_encoder_post_crtc_p
+       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);
+@@ -3724,6 +3726,8 @@ static int vc4_hdmi_runtime_suspend(stru
+       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;
+--- a/drivers/gpu/drm/vc4/vc4_hvs.c
++++ b/drivers/gpu/drm/vc4/vc4_hvs.c
+@@ -2308,7 +2308,10 @@ static void vc4_hvs_unbind(struct device
+               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;
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -376,6 +376,8 @@ static int vc4_v3d_runtime_suspend(struc
+       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/target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch b/target/linux/bcm27xx/patches-6.6/950-1324-dts-bcm2712-rpi-Add-aliases-for-the-CSI-DSI-I2Cs.patch
new file mode 100644 (file)
index 0000000..8781590
--- /dev/null
@@ -0,0 +1,71 @@
+From 36faab69e8eebfb7f587bddef96040c59d3daa7c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Wed, 16 Oct 2024 11:31:04 +0100
+Subject: [PATCH 1324/1350] dts: bcm2712-rpi: Add aliases for the CSI/DSI I2Cs
+
+Older Pis arrange that the camera I2C ports appear as /dev/i2c-10. Add
+aliases so that on the Pi 5 family, i2c_csi_dsi0 becomes i2c-10 and
+i2c_csi_dsi1 becomes i2c-11. Only the I2C buses that appear on the
+40-pin header, i.e. I2C0 to I2C3, get a low bus number.
+
+Also add hints for our udev rules about which symlinks to create for
+backwards-compatibility with the previous bus numbers. Note that
+lower numbers have priority, so i2c-0 on CM5 masks i2c-11, forcing
+i2c-11 to be a symlink to i2c-0, not vice versa.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts  | 2 ++
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 2 ++
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi     | 7 +++----
+ 3 files changed, 7 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -255,12 +255,14 @@ i2c_csi_dsi0: &i2c6 { // Note: This is f
+       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
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+@@ -238,9 +238,11 @@ i2c_csi_dsi0: &i2c6 { // Note: This is f
+       pinctrl-0 = <&rp1_i2c6_38_39>;
+       pinctrl-names = "default";
+       clock-frequency = <100000>;
++      symlink = "i2c-6";
+ };
+ i2c_csi_dsi1: &i2c0 { // Note: This is for MIPI1 connector
++      symlink = "i2c-11";
+ };
+ i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -117,12 +117,11 @@
+               i2c = &i2c_arm;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+-              i2c10 = &i2c_rp1boot;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+-              i2c4 = &i2c4;
+-              i2c5 = &i2c5;
+-              i2c6 = &i2c6;
++              i2c10 = &i2c_csi_dsi0;
++              i2c11 = &i2c_csi_dsi1;
++              i2c12 = &i2c_rp1boot;
+               mailbox = &mailbox;
+               mmc0 = &sdio1;
+               serial0 = &uart0;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch b/target/linux/bcm27xx/patches-6.6/950-1325-NotForUpstream-media-video-mux-Propagate-controls-to.patch
new file mode 100644 (file)
index 0000000..c40c3d2
--- /dev/null
@@ -0,0 +1,51 @@
+From e03a63b8d4a60ee49e3277ac7f7ea4c2998e7938 Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Thu, 10 Oct 2024 14:52:52 +0100
+Subject: [PATCH 1325/1350] NotForUpstream: media: video-mux: Propagate
+ controls to source
+
+The i.MX8MP makes calls on it's source device to determine
+the link-frequency that should be configured on the CSI2 receiver.
+
+When the source is behind a video mux, we need to pass this call through
+to the connected device.
+
+Map the control handler of the source device to the video-mux,
+essentially proxying all controls on the mux to the device which has
+it's link enabled.
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ drivers/media/platform/video-mux.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/media/platform/video-mux.c
++++ b/drivers/media/platform/video-mux.c
+@@ -69,6 +69,7 @@ static int video_mux_link_setup(struct m
+                               const struct media_pad *remote, u32 flags)
+ {
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++      struct v4l2_subdev *source_sd;
+       struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
+       u16 source_pad = entity->num_pads - 1;
+       int ret = 0;
+@@ -111,6 +112,10 @@ static int video_mux_link_setup(struct m
+               *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;
+@@ -118,6 +123,8 @@ static int video_mux_link_setup(struct m
+               dev_dbg(sd->dev, "going inactive\n");
+               mux_control_deselect(vmux->mux);
+               vmux->active = -1;
++
++              vmux->subdev.ctrl_handler = NULL;
+       }
+ out:
diff --git a/target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch b/target/linux/bcm27xx/patches-6.6/950-1326-media-platform-video-mux-Fix-mutex-locking.patch
new file mode 100644 (file)
index 0000000..12b08b8
--- /dev/null
@@ -0,0 +1,59 @@
+From cc0c868b51941f0ff2676970b70d388f1722e7fe Mon Sep 17 00:00:00 2001
+From: Paul Elder <paul.elder@ideasonboard.com>
+Date: Thu, 10 Oct 2024 14:52:53 +0100
+Subject: [PATCH 1326/1350] media: platform: video-mux: Fix mutex locking
+
+The current order of locking between the driver mutex and the v4l2
+subdev state lock causes a circuluar locking dependency when trying to
+set up a link. Fix this.
+
+Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ drivers/media/platform/video-mux.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/platform/video-mux.c
++++ b/drivers/media/platform/video-mux.c
+@@ -70,6 +70,7 @@ static int video_mux_link_setup(struct m
+ {
+       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;
+@@ -85,10 +86,10 @@ static int video_mux_link_setup(struct m
+               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)
+@@ -106,12 +107,10 @@ static int video_mux_link_setup(struct m
+               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;
+@@ -129,6 +128,7 @@ static int video_mux_link_setup(struct m
+ out:
+       mutex_unlock(&vmux->lock);
++      v4l2_subdev_unlock_state(sd_state);
+       return ret;
+ }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch b/target/linux/bcm27xx/patches-6.6/950-1327-media-i2c-ov5647-Tidy-up-mode-registers-to-make-the-.patch
new file mode 100644 (file)
index 0000000..3f0a34e
--- /dev/null
@@ -0,0 +1,94 @@
+From 664e835fd4886332ec3b3813de47102fe45e4fc3 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 15 Oct 2024 16:05:57 +0100
+Subject: [PATCH 1327/1350] media: i2c: ov5647: Tidy up mode registers to make
+ the order common
+
+To make comparisons of the mode registers easier, put the registers
+for the binned and VGA modes in the same order as the others.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 33 ++++++++++++++-------------------
+ 1 file changed, 14 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -344,6 +344,8 @@ static struct regval_list ov5647_2x2binn
+       {0x3036, 0x62},
+       {0x303c, 0x11},
+       {0x3106, 0xf5},
++      {0x3821, 0x01},
++      {0x3820, 0x41},
+       {0x3827, 0xec},
+       {0x370c, 0x03},
+       {0x3612, 0x59},
+@@ -416,8 +418,6 @@ static struct regval_list ov5647_2x2binn
+       {0x4837, 0x16},
+       {0x4800, 0x24},
+       {0x3503, 0x03},
+-      {0x3820, 0x41},
+-      {0x3821, 0x01},
+       {0x350a, 0x00},
+       {0x350b, 0x10},
+       {0x3500, 0x00},
+@@ -430,20 +430,27 @@ static struct regval_list ov5647_2x2binn
+ static struct regval_list ov5647_640x480_10bpp[] = {
+       {0x0100, 0x00},
+       {0x0103, 0x01},
+-      {0x3035, 0x11},
++      {0x3034, 0x1a},
++      {0x3035, 0x21},
+       {0x3036, 0x46},
+       {0x303c, 0x11},
++      {0x3106, 0xf5},
+       {0x3821, 0x01},
+       {0x3820, 0x41},
++      {0x3827, 0xec},
+       {0x370c, 0x03},
+       {0x3612, 0x59},
+       {0x3618, 0x00},
+       {0x5000, 0x06},
+       {0x5003, 0x08},
+       {0x5a00, 0x08},
+-      {0x3000, 0xff},
+-      {0x3001, 0xff},
+-      {0x3002, 0xff},
++      {0x3000, 0x00},
++      {0x3001, 0x00},
++      {0x3002, 0x00},
++      {0x3016, 0x08},
++      {0x3017, 0xe0},
++      {0x3018, 0x44},
++      {0x301c, 0xf8},
+       {0x301d, 0xf0},
+       {0x3a18, 0x00},
+       {0x3a19, 0xf8},
+@@ -469,6 +476,7 @@ static struct regval_list ov5647_640x480
+       {0x3632, 0xe2},
+       {0x3633, 0x23},
+       {0x3634, 0x44},
++      {0x3636, 0x06},
+       {0x3620, 0x64},
+       {0x3621, 0xe0},
+       {0x3600, 0x37},
+@@ -497,19 +505,6 @@ static struct regval_list ov5647_640x480
+       {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},
diff --git a/target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch b/target/linux/bcm27xx/patches-6.6/950-1328-media-i2c-ov5647-Separate-out-the-common-registers.patch
new file mode 100644 (file)
index 0000000..7f979e3
--- /dev/null
@@ -0,0 +1,392 @@
+From aef1e51838641a602e0ab60523283f8a6e36a725 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 15 Oct 2024 17:02:39 +0100
+Subject: [PATCH 1328/1350] media: i2c: ov5647: Separate out the common
+ registers.
+
+There are many registers in common between all the modes.
+Pull those out into one common table.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 243 ++++++++-----------------------------
+ 1 file changed, 50 insertions(+), 193 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -162,22 +162,16 @@ static const struct regval_list sensor_o
+       {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, 0x00},
+-      {0x3820, 0x00},
+       {0x3827, 0xec},
+       {0x370c, 0x03},
+-      {0x3612, 0x5b},
+-      {0x3618, 0x04},
+       {0x5000, 0x06},
+-      {0x5002, 0x41},
+       {0x5003, 0x08},
+       {0x5a00, 0x08},
+       {0x3000, 0x00},
+@@ -192,24 +186,6 @@ static struct regval_list ov5647_2592x19
+       {0x3a19, 0xf8},
+       {0x3c01, 0x80},
+       {0x3b07, 0x0c},
+-      {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},
+@@ -229,11 +205,6 @@ static struct regval_list ov5647_2592x19
+       {0x3f06, 0x10},
+       {0x3f01, 0x0a},
+       {0x3a08, 0x01},
+-      {0x3a09, 0x28},
+-      {0x3a0a, 0x00},
+-      {0x3a0b, 0xf6},
+-      {0x3a0d, 0x08},
+-      {0x3a0e, 0x06},
+       {0x3a0f, 0x58},
+       {0x3a10, 0x50},
+       {0x3a1b, 0x58},
+@@ -241,52 +212,57 @@ static struct regval_list ov5647_2592x19
+       {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},
++      {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},
+       {0x0100, 0x01},
+ };
+ static struct regval_list ov5647_1080p30_10bpp[] = {
+-      {0x0100, 0x00},
+-      {0x0103, 0x01},
+-      {0x3034, 0x1a},
+-      {0x3035, 0x21},
+       {0x3036, 0x62},
+-      {0x303c, 0x11},
+-      {0x3106, 0xf5},
+       {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},
+       {0x3814, 0x11},
+       {0x3815, 0x11},
+       {0x3708, 0x64},
+       {0x3709, 0x12},
+-      {0x3808, 0x07},
+-      {0x3809, 0x80},
+-      {0x380a, 0x04},
+-      {0x380b, 0x38},
+       {0x3800, 0x01},
+       {0x3801, 0x5c},
+       {0x3802, 0x01},
+@@ -295,77 +271,30 @@ static struct regval_list ov5647_1080p30
+       {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},
+       {0x3821, 0x01},
+       {0x3820, 0x41},
+-      {0x3827, 0xec},
+-      {0x370c, 0x03},
+       {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},
+@@ -382,42 +311,14 @@ static struct regval_list ov5647_2x2binn
+       {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},
+       {0x350a, 0x00},
+       {0x350b, 0x10},
+       {0x3500, 0x00},
+@@ -428,42 +329,15 @@ static struct regval_list ov5647_2x2binn
+ };
+ static struct regval_list ov5647_640x480_10bpp[] = {
+-      {0x0100, 0x00},
+-      {0x0103, 0x01},
+-      {0x3034, 0x1a},
+-      {0x3035, 0x21},
+       {0x3036, 0x46},
+-      {0x303c, 0x11},
+-      {0x3106, 0xf5},
+       {0x3821, 0x01},
+       {0x3820, 0x41},
+-      {0x3827, 0xec},
+-      {0x370c, 0x03},
+       {0x3612, 0x59},
+       {0x3618, 0x00},
+-      {0x5000, 0x06},
+-      {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},
+       {0x3814, 0x35},
+       {0x3815, 0x35},
+       {0x3708, 0x64},
+       {0x3709, 0x52},
+-      {0x3808, 0x02},
+-      {0x3809, 0x80},
+-      {0x380a, 0x01},
+-      {0x380b, 0xe0},
+       {0x3800, 0x00},
+       {0x3801, 0x10},
+       {0x3802, 0x00},
+@@ -472,41 +346,17 @@ static struct regval_list ov5647_640x480
+       {0x3805, 0x2f},
+       {0x3806, 0x07},
+       {0x3807, 0x9f},
+-      {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},
++      {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},
+       {0x4800, 0x34},
+-      {0x3503, 0x03},
+       {0x0100, 0x01},
+ };
+@@ -715,6 +565,13 @@ static int ov5647_set_mode(struct v4l2_s
+       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) {
diff --git a/target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch b/target/linux/bcm27xx/patches-6.6/950-1329-media-i2c-ov5647-Use-the-same-PLL-config-for-full-10.patch
new file mode 100644 (file)
index 0000000..c272951
--- /dev/null
@@ -0,0 +1,53 @@
+From 35e5c3d706cbe686e3468d9f24ae999212553893 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 15 Oct 2024 19:36:13 +0100
+Subject: [PATCH 1329/1350] media: i2c: ov5647: Use the same PLL config for
+ full, 1080p, and binned modes
+
+In order to simplify the driver slightly, use the same PLL
+configuration, and hence pixel rate and link frequency (to be
+added) for the full, 1080p, and binned modes.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -253,7 +253,7 @@ static struct regval_list ov5647_2592x19
+ };
+ static struct regval_list ov5647_1080p30_10bpp[] = {
+-      {0x3036, 0x62},
++      {0x3036, 0x69},
+       {0x3821, 0x00},
+       {0x3820, 0x00},
+       {0x3612, 0x5b},
+@@ -289,7 +289,7 @@ static struct regval_list ov5647_1080p30
+ };
+ static struct regval_list ov5647_2x2binned_10bpp[] = {
+-      {0x3036, 0x62},
++      {0x3036, 0x69},
+       {0x3821, 0x01},
+       {0x3820, 0x41},
+       {0x3612, 0x59},
+@@ -397,7 +397,7 @@ static const struct ov5647_mode ov5647_m
+                       .width          = 1928,
+                       .height         = 1080,
+               },
+-              .pixel_rate     = 81666700,
++              .pixel_rate     = 87500000,
+               .hts            = 2416,
+               .vts            = 0x450,
+               .reg_list       = ov5647_1080p30_10bpp,
+@@ -418,7 +418,7 @@ static const struct ov5647_mode ov5647_m
+                       .width          = 2592,
+                       .height         = 1944,
+               },
+-              .pixel_rate     = 81666700,
++              .pixel_rate     = 87500000,
+               .hts            = 1896,
+               .vts            = 0x59b,
+               .reg_list       = ov5647_2x2binned_10bpp,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch b/target/linux/bcm27xx/patches-6.6/950-1330-media-i2c-ov5647-Add-V4L2_CID_LINK_FREQUENCY-control.patch
new file mode 100644 (file)
index 0000000..efe4759
--- /dev/null
@@ -0,0 +1,111 @@
+From 84ab77459e61c648299d32464127b89ca65de40a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 15 Oct 2024 19:46:01 +0100
+Subject: [PATCH 1330/1350] media: i2c: ov5647: Add V4L2_CID_LINK_FREQUENCY
+ control
+
+The link frequency can vary between modes, so add it as a
+control.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 25 ++++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -97,6 +97,13 @@ static const char * const ov5647_supply_
+ #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;
+@@ -106,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;
+@@ -128,6 +136,7 @@ struct ov5647 {
+       struct v4l2_ctrl                *exposure;
+       struct v4l2_ctrl                *hflip;
+       struct v4l2_ctrl                *vflip;
++      struct v4l2_ctrl                *link_freq;
+       bool                            streaming;
+ };
+@@ -377,6 +386,7 @@ static const struct ov5647_mode ov5647_m
+                       .height         = 1944
+               },
+               .pixel_rate     = 87500000,
++              .link_freq_index = FREQ_INDEX_FULL,
+               .hts            = 2844,
+               .vts            = 0x7b0,
+               .reg_list       = ov5647_2592x1944_10bpp,
+@@ -398,6 +408,7 @@ static const struct ov5647_mode ov5647_m
+                       .height         = 1080,
+               },
+               .pixel_rate     = 87500000,
++              .link_freq_index = FREQ_INDEX_FULL,
+               .hts            = 2416,
+               .vts            = 0x450,
+               .reg_list       = ov5647_1080p30_10bpp,
+@@ -419,6 +430,7 @@ static const struct ov5647_mode ov5647_m
+                       .height         = 1944,
+               },
+               .pixel_rate     = 87500000,
++              .link_freq_index = FREQ_INDEX_FULL,
+               .hts            = 1896,
+               .vts            = 0x59b,
+               .reg_list       = ov5647_2x2binned_10bpp,
+@@ -440,6 +452,7 @@ static const struct ov5647_mode ov5647_m
+                       .height         = 1920,
+               },
+               .pixel_rate     = 55000000,
++              .link_freq_index = FREQ_INDEX_VGA,
+               .hts            = 1852,
+               .vts            = 0x1f8,
+               .reg_list       = ov5647_640x480_10bpp,
+@@ -943,6 +956,8 @@ static int ov5647_set_pad_fmt(struct v4l
+                                        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. */
+@@ -1248,7 +1263,7 @@ static int ov5647_init_controls(struct o
+       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, 10);
+       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+                         V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
+@@ -1308,6 +1323,14 @@ static int ov5647_init_controls(struct o
+       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,
diff --git a/target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch b/target/linux/bcm27xx/patches-6.6/950-1331-mmc-don-t-reference-requests-after-finishing-them.patch
new file mode 100644 (file)
index 0000000..c7d411f
--- /dev/null
@@ -0,0 +1,71 @@
+From b80d5d1d5148a89121e3759bb4caa27e7ee1cf05 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Tue, 15 Oct 2024 11:22:53 +0100
+Subject: [PATCH 1331/1350] mmc: don't reference requests after finishing them
+
+Posted write tracking introduced in the commit below raced with re-use
+of the requests between completion and submission, potentially causing
+underflow of the pending write count.
+
+Fixes: e6c1e862b2b8 ("mmc: restrict posted write counts for SD cards in CQ mode")
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/block.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1524,6 +1524,7 @@ static void mmc_blk_cqe_complete_rq(stru
+       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;
+@@ -1555,7 +1556,7 @@ static void mmc_blk_cqe_complete_rq(stru
+       spin_lock_irqsave(&mq->lock, flags);
+-      if (req_op(req) == REQ_OP_WRITE)
++      if (write)
+               mq->pending_writes--;
+       mq->in_flight[issue_type] -= 1;
+@@ -2170,15 +2171,16 @@ static void mmc_blk_mq_poll_completion(s
+ }
+ static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type,
+-                                   struct request *req)
++                                   bool write)
+ {
+       unsigned long flags;
+       bool put_card;
+       spin_lock_irqsave(&mq->lock, flags);
+-      if (req_op(req) == REQ_OP_WRITE)
++      if (write)
+               mq->pending_writes--;
++
+       mq->in_flight[issue_type] -= 1;
+       put_card = (mmc_tot_in_flight(mq) == 0);
+@@ -2193,6 +2195,7 @@ static void mmc_blk_mq_post_req(struct m
+                               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;
+@@ -2212,7 +2215,7 @@ static void mmc_blk_mq_post_req(struct m
+                       blk_mq_complete_request(req);
+       }
+-      mmc_blk_mq_dec_in_flight(mq, issue_type, req);
++      mmc_blk_mq_dec_in_flight(mq, issue_type, write);
+ }
+ void mmc_blk_mq_recovery(struct mmc_queue *mq)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch b/target/linux/bcm27xx/patches-6.6/950-1333-mmc-quirks-disable-cache-on-more-known-bad-Sandisk-c.patch
new file mode 100644 (file)
index 0000000..109c502
--- /dev/null
@@ -0,0 +1,35 @@
+From 4d702b5c68d6449d81281677f71de557f64cdce5 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Tue, 15 Oct 2024 14:35:42 +0100
+Subject: [PATCH 1333/1350] mmc: quirks: disable cache on more known-bad
+ Sandisk card date ranges
+
+Cards with manufacture dates in 2019 and 2020 have been seen in the wild
+that hang indefinitely if issued a cache flush command in CQ mode.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/quirks.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -33,6 +33,18 @@ static const struct mmc_fixup __maybe_un
+                  0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+                  MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
++      /*
++       * 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),
++
++      _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
+ };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch b/target/linux/bcm27xx/patches-6.6/950-1334-mmc-block-disable-CQ-on-SD-cards-when-doing-non-Disc.patch
new file mode 100644 (file)
index 0000000..72a87e5
--- /dev/null
@@ -0,0 +1,55 @@
+From 73ddacb555c5ef1f063f44b4ec3268da899ff8b5 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 18 Oct 2024 13:11:11 +0100
+Subject: [PATCH 1334/1350] mmc: block: disable CQ on SD cards when doing
+ non-Discard erase
+
+Only CMD38 with Arg=0x1 (Discard) is supported when in CQ mode, so
+turn it off before issuing a non-discard erase op.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/block.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1177,12 +1177,26 @@ static void mmc_blk_issue_erase_rq(struc
+       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);
+@@ -1203,6 +1217,11 @@ static void mmc_blk_issue_erase_rq(struc
+               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);
+ }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch b/target/linux/bcm27xx/patches-6.6/950-1335-DTS-bcm2712-re-enable-SD-slot-CQE-by-default-on-Pi-5.patch
new file mode 100644 (file)
index 0000000..e6260e7
--- /dev/null
@@ -0,0 +1,39 @@
+From 48a15bc46004025776880a091d47a22e03449acc Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 18 Oct 2024 14:06:01 +0100
+Subject: [PATCH 1335/1350] DTS: bcm2712; re-enable SD slot CQE by default on
+ Pi 5
+
+This reverts commit 1b92c9369569137d8f2b8bf82884a05999e1f73b.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/README                | 6 +++---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 1 +
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -378,9 +378,9 @@ Params:
+                                 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
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -365,6 +365,7 @@ dpi_16bit_gpio2:        &rp1_dpi_16bit_g
+       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";
diff --git a/target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch b/target/linux/bcm27xx/patches-6.6/950-1336-mmc-quirks-add-MMC_QUIRK_BROKEN_ERASE-for-Phison-Int.patch
new file mode 100644 (file)
index 0000000..ba61b15
--- /dev/null
@@ -0,0 +1,33 @@
+From 527d6f5a7861e24c60d41e9706ec4589165321d1 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+Date: Fri, 18 Oct 2024 16:01:28 +0100
+Subject: [PATCH 1336/1350] mmc: quirks: add MMC_QUIRK_BROKEN_ERASE for
+ Phison/Integral cards
+
+Recent Integral cards end up with corrupt sectors after a flash erase.
+This covers sizes for the A2 range, which can't be differentiated from
+the A1 range which might not have the same issue.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
+---
+ drivers/mmc/core/quirks.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -162,6 +162,15 @@ static const struct mmc_fixup __maybe_un
+       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/target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch b/target/linux/bcm27xx/patches-6.6/950-1337-Input-matrix_keypad-avoid-repeatedly-converting-GPIO.patch
new file mode 100644 (file)
index 0000000..d9a7a10
--- /dev/null
@@ -0,0 +1,155 @@
+From 25b2b36dea57fd86b63df2e253b376532d314a30 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Sat, 20 Jan 2024 21:32:28 -0800
+Subject: [PATCH 1337/1350] Input: matrix_keypad - avoid repeatedly converting
+ GPIO to IRQ
+
+commit a96fb711c6be76bcfbcf594a865002fa7c0eb525 upstream.
+
+There is no need to do conversion from GPIOs to interrupt numbers.
+Convert row GPIOs to interrupt numbers once in probe() and use
+this information when the driver needs to enable or disable given
+interrupt line.
+
+Link: https://lore.kernel.org/r/20240121053232.276968-1-dmitry.torokhov@gmail.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/keyboard/matrix_keypad.c | 48 ++++++++++++++------------
+ 1 file changed, 25 insertions(+), 23 deletions(-)
+
+--- 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 matri
+               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 matr
+               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 in
+ 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(
+                       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
+                       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(struc
+                                  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(struc
+               }
+       } 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;
++                      }
++
++                      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(struc
+                                       pdata->row_gpios[i]);
+                               goto err_free_irqs;
+                       }
++
++                      keypad->row_irqs[i] = irq;
+               }
+       }
+@@ -366,7 +368,7 @@ static int matrix_keypad_init_gpio(struc
+ 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(stru
+               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);
+       }
+       for (i = 0; i < pdata->num_row_gpios; i++)
diff --git a/target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch b/target/linux/bcm27xx/patches-6.6/950-1338-numa-Add-simple-generic-NUMA-emulation.patch
new file mode 100644 (file)
index 0000000..afb1bf7
--- /dev/null
@@ -0,0 +1,182 @@
+From b1a0f9c705912ec0434645f2d2bcf914c635564d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+Date: Fri, 17 May 2024 11:40:23 -0300
+Subject: [PATCH 1338/1350] numa: Add simple generic NUMA emulation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add some common code for splitting the memory into N emulated NUMA memory
+nodes.
+
+Individual architecture can then enable selecting this option and use the
+existing numa=fake=<N> kernel argument to enable it.
+
+Memory is always split into equally sized chunks.
+
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+Co-developed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: “Rafael J. Wysocki" <rafael@kernel.org>
+---
+ drivers/base/Kconfig          |  7 ++++
+ drivers/base/Makefile         |  1 +
+ drivers/base/arch_numa.c      |  6 ++++
+ drivers/base/numa_emulation.c | 67 +++++++++++++++++++++++++++++++++++
+ drivers/base/numa_emulation.h | 21 +++++++++++
+ 5 files changed, 102 insertions(+)
+ create mode 100644 drivers/base/numa_emulation.c
+ create mode 100644 drivers/base/numa_emulation.h
+
+--- 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
+--- a/drivers/base/Makefile
++++ b/drivers/base/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_DEV_COREDUMP) += devcoredum
+ 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/
+--- a/drivers/base/arch_numa.c
++++ b/drivers/base/arch_numa.c
+@@ -15,6 +15,8 @@
+ #include <asm/sections.h>
++#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
+               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;
+ }
+@@ -471,6 +475,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);
+--- /dev/null
++++ b/drivers/base/numa_emulation.c
+@@ -0,0 +1,67 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Simple NUMA emulation.
++ *
++ * Copyright © 2024 Raspberry Pi Ltd
++ *
++ * Author: Maíra Canal <mcanal@igalia.com>
++ * Author: Tvrtko Ursulin <tursulin@igalia.com>
++ */
++#include <linux/memblock.h>
++
++#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;
++
++              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;
++}
+--- /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/target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch b/target/linux/bcm27xx/patches-6.6/950-1339-arm64-numa-Add-NUMA-emulation-for-ARM64.patch
new file mode 100644 (file)
index 0000000..169706d
--- /dev/null
@@ -0,0 +1,39 @@
+From 462346142b26dd1fd8f55655959e38b385acb1c1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+Date: Fri, 17 May 2024 11:40:34 -0300
+Subject: [PATCH 1339/1350] arm64/numa: Add NUMA emulation for ARM64
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Allow selecting NUMA emulation on arm64.
+
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: “Rafael J. Wysocki" <rafael@kernel.org>
+---
+ arch/arm64/Kconfig | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -1500,6 +1500,16 @@ config NODES_SHIFT
+         Specify the maximum number of NUMA Nodes available on the target
+         system.  Increases memory reserved to accommodate various tables.
++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/target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch b/target/linux/bcm27xx/patches-6.6/950-1340-mm-numa-Allow-override-of-kernel-s-default-NUMA-poli.patch
new file mode 100644 (file)
index 0000000..f0de0ce
--- /dev/null
@@ -0,0 +1,115 @@
+From 4bbdd9335a4784743a5ac30697f24972219559c2 Mon Sep 17 00:00:00 2001
+From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Date: Wed, 22 May 2024 17:12:16 +0100
+Subject: [PATCH 1340/1350] mm/numa: Allow override of kernel's default NUMA
+ policy
+
+Add numa_policy kernel argument to allow overriding the kernel's default
+NUMA policy at boot time.
+
+Syntax identical to what tmpfs accepts as it's mpol argument is accepted.
+
+Some examples:
+
+ numa_policy=interleave
+ numa_policy=interleave=skip-interleave
+ numa_policy=bind:0-3,5,7,9-15
+ numa_policy=bind=static:1-2
+
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+---
+ mm/mempolicy.c | 49 ++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 42 insertions(+), 7 deletions(-)
+
+--- a/mm/mempolicy.c
++++ b/mm/mempolicy.c
+@@ -2974,7 +2974,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);
+ }
+ /*
+@@ -2992,7 +2994,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
+@@ -3005,13 +3006,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 */
+@@ -3090,9 +3096,16 @@ int mpol_parse_str(char *str, struct mem
+                       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
+@@ -3125,7 +3138,29 @@ out:
+               *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/target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch b/target/linux/bcm27xx/patches-6.6/950-1341-dma-buf-system_heap-Allow-specifying-maximum-allocat.patch
new file mode 100644 (file)
index 0000000..db2268e
--- /dev/null
@@ -0,0 +1,46 @@
+From 56fda5adce0c9b4dc8ff2c7be9a704599e685001 Mon Sep 17 00:00:00 2001
+From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Date: Wed, 17 Jul 2024 09:33:21 +0100
+Subject: [PATCH 1341/1350] dma-buf: system_heap: Allow specifying maximum
+ allocation order
+
+system_heap.max_order=<uint>
+
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+---
+ drivers/dma-buf/heaps/system_heap.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- 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
+ 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_alloc
+       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/target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch b/target/linux/bcm27xx/patches-6.6/950-1342-numa-emulation-Check-emulated-zones-around-the-CMA-w.patch
new file mode 100644 (file)
index 0000000..cc459b6
--- /dev/null
@@ -0,0 +1,95 @@
+From a27d76f4517d56a6471def2f76687e83fd2a7923 Mon Sep 17 00:00:00 2001
+From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Date: Mon, 29 Jul 2024 16:53:18 +0100
+Subject: [PATCH 1342/1350] numa/emulation: Check emulated zones around the CMA
+ window
+
+... Make sure CMA zones do not straddle the emulated NUMA nodes ...
+
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+---
+ drivers/base/numa_emulation.c |  5 +++++
+ include/linux/cma.h           | 10 ++++++++++
+ mm/cma.c                      | 36 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 51 insertions(+)
+
+--- a/drivers/base/numa_emulation.c
++++ b/drivers/base/numa_emulation.c
+@@ -7,6 +7,7 @@
+  * Author: Maíra Canal <mcanal@igalia.com>
+  * Author: Tvrtko Ursulin <tursulin@igalia.com>
+  */
++#include <linux/cma.h>
+ #include <linux/memblock.h>
+ #include "numa_emulation.h"
+@@ -55,6 +56,10 @@ int __init numa_emu_init(void)
+               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) {
+--- a/include/linux/cma.h
++++ b/include/linux/cma.h
+@@ -56,4 +56,14 @@ extern bool cma_release(struct cma *cma,
+ 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
++
+ #endif
+--- a/mm/cma.c
++++ b/mm/cma.c
+@@ -587,3 +587,39 @@ int cma_for_each_area(int (*it)(struct c
+       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/target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch b/target/linux/bcm27xx/patches-6.6/950-1344-dts-Move-some-common-rpi-settings-into-rpi-files.patch
new file mode 100644 (file)
index 0000000..26c052c
--- /dev/null
@@ -0,0 +1,97 @@
+From aece59283a161dfad67c700c2ae97f9dd996eb2f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 23 Jul 2024 15:55:54 +0100
+Subject: [PATCH 1344/1350] dts: Move some common rpi settings into rpi files
+
+Most 2711 devices and all 2712 device share common bootargs (command
+lines). Make the common values shared defaults, overriding them were
+necessary.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts    | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts    | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi    | 1 +
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts  | 5 -----
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 5 -----
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi     | 5 +++++
+ 6 files changed, 6 insertions(+), 18 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts
+@@ -265,10 +265,6 @@
+ #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;
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
+@@ -274,10 +274,6 @@
+ #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;
+ };
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
+@@ -3,6 +3,7 @@
+ / {
+       chosen: chosen {
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
+       };
+       __overrides__ {
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+@@ -432,11 +432,6 @@ dpi_16bit_gpio2:        &rp1_dpi_16bit_g
+ };
+ / {
+-      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";
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+@@ -422,11 +422,6 @@ dpi_16bit_gpio2:        &rp1_dpi_16bit_g
+ };
+ / {
+-      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";
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -98,6 +98,11 @@
+ };
+ / {
++      chosen: chosen {
++              bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
++              stdout-path = "serial10:115200n8";
++      };
++
+       aliases: aliases {
+               blconfig = &blconfig;
+               blpubkey = &blpubkey;
diff --git a/target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch b/target/linux/bcm27xx/patches-6.6/950-1345-dts-Set-preferred-numa-options-in-bootargs.patch
new file mode 100644 (file)
index 0000000..727c1a3
--- /dev/null
@@ -0,0 +1,52 @@
+From dd44b93200c412c4c043392243c417f2d70082b3 Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Thu, 18 Jul 2024 20:22:18 +0100
+Subject: [PATCH 1345/1350] dts: Set preferred numa options in bootargs
+
+The default cmdline adjustment is now numa_policy=interleave for 2711 and 2712,
+and additionally system_heap.max_order=0 iommu_dma_numa_policy=interleave for
+just 2712 (due to its better iommu support).
+
+The key setting numa=fake=<n> is not set here, so we will boot with a single
+numa region and behaviour should be pretty much unchanged from before this PR.
+
+Signed-off-by: Dom Cobley <popcornmix@gmail.com>
+---
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts | 2 +-
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi  | 2 +-
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi   | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
+@@ -148,7 +148,7 @@
+ / {
+       chosen {
+-              bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0";
++              bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 numa_policy=interleave";
+       };
+       aliases {
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
+@@ -3,7 +3,7 @@
+ / {
+       chosen: chosen {
+-              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave";
+       };
+       __overrides__ {
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -99,7 +99,7 @@
+ / {
+       chosen: chosen {
+-              bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe";
++              bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0";
+               stdout-path = "serial10:115200n8";
+       };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch b/target/linux/bcm27xx/patches-6.6/950-1346-drm-vc4-Do-not-include-writeback-conn-load-in-load-t.patch
new file mode 100644 (file)
index 0000000..1a7c5f6
--- /dev/null
@@ -0,0 +1,48 @@
+From a2c8327a1b534574d51f5ea42009876e0008efd2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 9 Sep 2024 17:28:00 +0100
+Subject: [PATCH 1346/1350] drm/vc4: Do not include writeback conn load in load
+ tracker
+
+The transposer/writeback connector should be running with a
+lower priority, so shouldn't be factored into the load
+calculations.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -674,17 +674,26 @@ static int vc4_load_tracker_atomic_check
+       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;
++                      }
+               }
+       }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch b/target/linux/bcm27xx/patches-6.6/950-1347-drm-vc4-Drop-panic-priority-for-writeback-connector.patch
new file mode 100644 (file)
index 0000000..91187d2
--- /dev/null
@@ -0,0 +1,54 @@
+From 2e85eb0e4950c5ad27df5a3ba54300e89694eba4 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 9 Sep 2024 17:38:45 +0100
+Subject: [PATCH 1347/1350] drm/vc4: Drop panic priority for writeback
+ connector
+
+As the writeback connector doesn't have the same realtime
+constraints of a live display, drop the panic priority for it.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -224,7 +224,7 @@ static void vc4_hvs_pv_muxing_commit(str
+               struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+               struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
+               u32 dispctrl;
+-              u32 dsp3_mux;
++              u32 dsp3_mux_pri;
+               if (!crtc_state->active)
+                       continue;
+@@ -241,15 +241,22 @@ static void vc4_hvs_pv_muxing_commit(str
+                * 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);
+       }
+ }
diff --git a/target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch b/target/linux/bcm27xx/patches-6.6/950-1348-dts-Simplify-bootargs.patch
new file mode 100644 (file)
index 0000000..f6de599
--- /dev/null
@@ -0,0 +1,112 @@
+From 8334494807ff5de7e500cb22e078c08754341c26 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 25 Oct 2024 10:36:20 +0100
+Subject: [PATCH 1348/1350] dts: Simplify bootargs
+
+Reduce the number of different places that bootargs is set in Pi dts
+files. The variants are all combinations of with/without Bluetooth
+and with/without NUMA support (2711).
+
+This is effectively a cosmetic change - the resulting dtbs are
+unchanged.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi      | 4 ++++
+ arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts   | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts      | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts | 4 ----
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi      | 2 +-
+ arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi      | 4 ++++
+ 7 files changed, 9 insertions(+), 17 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi
+@@ -23,6 +23,10 @@
+ };
+ / {
++      chosen {
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
++      };
++
+       aliases {
+               bluetooth = &bt;
+       };
+--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-zero-w.dts
+@@ -11,10 +11,6 @@
+       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;
+--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts
+@@ -12,10 +12,6 @@
+       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;
+--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-3-b.dts
+@@ -12,10 +12,6 @@
+       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;
+--- a/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2710-rpi-zero-2-w.dts
+@@ -11,10 +11,6 @@
+       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;
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
+@@ -2,7 +2,7 @@
+ #include "bcm270x-rpi.dtsi"
+ / {
+-      chosen: chosen {
++      chosen {
+               bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave";
+       };
+--- a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi
+@@ -23,6 +23,10 @@
+ };
+ / {
++      chosen {
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
++      };
++
+       aliases {
+               bluetooth = &bt;
+       };
diff --git a/target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch b/target/linux/bcm27xx/patches-6.6/950-1349-cgroup-Use-kernel-command-line-to-disable-memory-cgr.patch
new file mode 100644 (file)
index 0000000..46e0aea
--- /dev/null
@@ -0,0 +1,193 @@
+From 86099deff5abf5f63643eecaedb4c11ae77474ce Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+Date: Thu, 24 Oct 2024 08:03:19 -0300
+Subject: [PATCH 1349/1350] cgroup: Use kernel command line to disable memory
+ cgroup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 94a23e978235 ("cgroup: Disable cgroup "memory" by default")
+disabled the memory cgroup by default when initing the cgroups. However,
+it's possible to disable the memory cgroup by a kernel command line.
+Hard-coding such a feature can be problematic as some memory management
+features depend on the order that things are set.
+
+For example, it is possible to see a NULL pointer dereference caused by
+commit 94a23e978235cd35f38075072b34152b2b667e6e. The NULL pointer
+dereference is triggered by the memory shrinker and ends up in a kernel
+crash.
+
+[   50.028629] ==================================================================
+[   50.028645] BUG: KASAN: null-ptr-deref in do_shrink_slab+0x1fc/0x978
+[   50.028663] Write of size 8 at addr 0000000000000000 by task gfxrecon-replay/1965
+
+[   50.028676] CPU: 3 UID: 1000 PID: 1965 Comm: gfxrecon-replay Tainted: G         C         6.12.0-rc4-v8-thp-kasan+ #85
+[   50.028685] Tainted: [C]=CRAP
+[   50.028689] Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT)
+[   50.028694] Call trace:
+[   50.028697]  dump_backtrace+0xfc/0x120
+[   50.028706]  show_stack+0x24/0x38
+[   50.028711]  dump_stack_lvl+0x40/0x88
+[   50.028720]  print_report+0xe4/0x708
+[   50.028728]  kasan_report+0xcc/0x130
+[   50.028733]  kasan_check_range+0x254/0x298
+[   50.028738]  __kasan_check_write+0x20/0x30
+[   50.028745]  do_shrink_slab+0x1fc/0x978
+[   50.028751]  shrink_slab+0x318/0xc38
+[   50.028756]  shrink_one+0x254/0x6d8
+[   50.028762]  shrink_node+0x26b4/0x2848
+[   50.028767]  do_try_to_free_pages+0x3e4/0x1190
+[   50.028773]  try_to_free_pages+0x5a4/0xb40
+[   50.028778]  __alloc_pages_direct_reclaim+0x144/0x298
+[   50.028787]  __alloc_pages_slowpath+0x5c4/0xc70
+[   50.028793]  __alloc_pages_noprof+0x4a8/0x6a8
+[   50.028800]  __folio_alloc_noprof+0x24/0xa8
+[   50.028806]  shmem_alloc_and_add_folio+0x2ec/0xce0
+[   50.028812]  shmem_get_folio_gfp+0x380/0xc20
+[   50.028818]  shmem_read_folio_gfp+0xe0/0x160
+[   50.028824]  drm_gem_get_pages+0x238/0x620 [drm]
+[   50.029039]  drm_gem_shmem_get_pages_sgt+0xd8/0x4b8 [drm_shmem_helper]
+[   50.029053]  v3d_bo_create_finish+0x58/0x1e0 [v3d]
+[   50.029083]  v3d_create_bo_ioctl+0xac/0x210 [v3d]
+[   50.029105]  drm_ioctl_kernel+0x1d8/0x2b8 [drm]
+[   50.029220]  drm_ioctl+0x4b4/0x920 [drm]
+[   50.029330]  __arm64_sys_ioctl+0x11c/0x160
+[   50.029337]  invoke_syscall+0x88/0x268
+[   50.029345]  el0_svc_common+0x160/0x1d8
+[   50.029351]  do_el0_svc+0x50/0x68
+[   50.029358]  el0_svc+0x34/0x80
+[   50.029364]  el0t_64_sync_handler+0x84/0x100
+[   50.029371]  el0t_64_sync+0x190/0x198
+[   50.029376] ==================================================================
+
+This happens because the memory shrinker is unaware that we are
+artificially disabling the memory cgroups and therefore it doesn't
+allocate `nr_deferred` (as it would if we used the kernel command line).
+
+To avoid such an issue, revert the artificial disablement and disable it
+through the command line. If a user wants to enable the feature, it can
+use the `cgroup_enable=` command line.
+
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+---
+ arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi  |  2 +-
+ arch/arm/boot/dts/broadcom/bcm270x.dtsi         |  2 +-
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts |  2 +-
+ arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi  |  2 +-
+ arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi  |  2 +-
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi   |  2 +-
+ kernel/cgroup/cgroup.c                          | 15 +--------------
+ 7 files changed, 7 insertions(+), 20 deletions(-)
+
+--- a/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2708-rpi-bt.dtsi
+@@ -24,7 +24,7 @@
+ / {
+       chosen {
+-              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory";
+       };
+       aliases {
+--- a/arch/arm/boot/dts/broadcom/bcm270x.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm270x.dtsi
+@@ -4,7 +4,7 @@
+ / {
+       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";
+       };
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4s.dts
+@@ -148,7 +148,7 @@
+ / {
+       chosen {
+-              bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 numa_policy=interleave";
++              bootargs = "coherent_pool=1M snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave";
+       };
+       aliases {
+--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
+@@ -3,7 +3,7 @@
+ / {
+       chosen {
+-              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 numa_policy=interleave";
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave";
+       };
+       __overrides__ {
+--- a/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi
++++ b/arch/arm/boot/dts/broadcom/bcm271x-rpi-bt.dtsi
+@@ -24,7 +24,7 @@
+ / {
+       chosen {
+-              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0";
++              bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory";
+       };
+       aliases {
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
+@@ -99,7 +99,7 @@
+ / {
+       chosen: chosen {
+-              bootargs = "reboot=w coherent_pool=1M 8250.nr_uarts=1 pci=pcie_bus_safe numa_policy=interleave iommu_dma_numa_policy=interleave system_heap.max_order=0";
++              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";
+       };
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -6060,9 +6060,6 @@ 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
+  *
+@@ -6096,12 +6093,6 @@ 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 =
+@@ -6742,10 +6733,6 @@ static int __init cgroup_disable(char *s
+                           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);
+@@ -6779,7 +6766,7 @@ static int __init cgroup_enable(char *st
+                           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);
diff --git a/target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch b/target/linux/bcm27xx/patches-6.6/950-1350-arm64-dts-Sort-out-CM5-and-I-O-board-I2C-ports.patch
new file mode 100644 (file)
index 0000000..8ee3b75
--- /dev/null
@@ -0,0 +1,185 @@
+From 4622323f5c9e540f3356f2229c4d551b31cc234d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 24 Oct 2024 15:38:36 +0100
+Subject: [PATCH 1350/1350] arm64: dts: Sort out CM5 and I/O board I2C ports
+
+There is a difference in I2C usage between CM4IO and CM5IO. Present a
+simple, consistent view of the world by moving the assignment of the
+bus IDs into carrier-specific files.
+
+CM5 has reduced connectivity on CM4IO - the DPHYs are connected to
+CAM1 and DISP1. Keep i2c-10 for use with that pair, as is the case for
+CM4 on CM4IO.
+
+Fixes: 36faab69e8ee ("dts: bcm2712-rpi: Add aliases for the CSI/DSI I2Cs")
+See: https://github.com/raspberrypi/linux/pull/6421
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ .../boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi  | 28 +++++++++++++++++++
+ .../dts/broadcom/bcm2712-rpi-cm5-cm4io.dts    | 17 +----------
+ .../dts/broadcom/bcm2712-rpi-cm5-cm5io.dts    |  7 +----
+ .../boot/dts/broadcom/bcm2712-rpi-cm5.dtsi    | 13 ---------
+ .../boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi  | 14 ++++++++++
+ .../dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts   | 17 +----------
+ .../dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts   |  7 +----
+ .../boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi   |  4 ---
+ 8 files changed, 46 insertions(+), 61 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm4io.dtsi
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5io.dtsi
+
+--- /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";
++};
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm4io.dts
+@@ -2,19 +2,4 @@
+ /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";
+-      };
+-};
++#include "bcm2712-rpi-cm4io.dtsi"
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5-cm5io.dts
+@@ -2,9 +2,4 @@
+ /dts-v1/;
+ #include "bcm2712-rpi-cm5.dtsi"
+-
+-/ {
+-      __overrides__ {
+-              i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+-      };
+-};
++#include "bcm2712-rpi-cm5io.dtsi"
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+@@ -234,19 +234,6 @@ aux: &dummy {};
+ #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: &i2c0 { // Note: This is for MIPI1 connector
+-      symlink = "i2c-11";
+-};
+-
+-i2c_csi_dsi: &i2c_csi_dsi1 { }; // An alias for compatibility
+-
+ cam1_reg: &cam0_reg { // Shares CAM_GPIO with cam0_reg
+ };
+--- /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
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm4io.dts
+@@ -2,19 +2,4 @@
+ /dts-v1/;
+ #include "bcm2712-rpi-cm5l.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";
+-      };
+-};
++#include "bcm2712-rpi-cm4io.dtsi"
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l-cm5io.dts
+@@ -2,9 +2,4 @@
+ /dts-v1/;
+ #include "bcm2712-rpi-cm5l.dtsi"
+-
+-/ {
+-      __overrides__ {
+-              i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+-      };
+-};
++#include "bcm2712-rpi-cm5io.dtsi"
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5l.dtsi
+@@ -5,10 +5,6 @@
+ / {
+       model = "Raspberry Pi Compute Module 5 Lite";
+-
+-      __overrides__ {
+-              i2c_csi_dsi = <&i2c_csi_dsi>, "status";
+-      };
+ };
+ &sd_io_1v8_reg {