From 5872633b9d3e0b6838fde2ce8fb78da025999e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 15 Mar 2025 11:43:43 +0100 Subject: [PATCH] bcm27xx: pull 6.6 patches from RPi repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds latest 6.6 patches from the Raspberry Pi repository. These patches were generated from: https://github.com/raspberrypi/linux/commits/rpi-6.6.y/ With the following command: git format-patch -N v6.6.83..HEAD (HEAD -> 08d4e8f52256bd422d8a1f876411603f627d0a82) Signed-off-by: Álvaro Fernández Rojas (cherry picked from commit 251f76c1c67d62c585d799c38dab31e1385d2ad5) --- ...-add-FS-LS-bus-instance-parkmode-dis.patch | 10 +- ...d-support-for-setting-NAK-enhancemen.patch | 10 +- ...pdate-files-for-pwm-gpio-fan-overlay.patch | 246 ++ ...-Limit-analogue-gain-according-to-mo.patch | 71 + ...s-sony-imx290-Add-IMX462-to-the-IMX2.patch | 31 + ...-imx290-Add-configuration-for-IMX462.patch | 116 + ...-module-parameter-to-allow-selection.patch | 60 + ...h-imx462-overlay-to-use-the-new-comp.patch | 47 + ...imx415-Add-more-clock-configurations.patch | 327 +++ ...overlay-for-Sony-IMX415-image-sensor.patch | 214 ++ ...415-Add-read-write-control-of-VBLANK.patch | 146 ++ ...-Make-HBLANK-controllable-and-in-con.patch | 231 ++ ...-Link-frequencies-are-not-exclusive-.patch | 136 ++ ...cm2711-PL011-UARTs-are-actually-r1p5.patch | 60 + ...cm2712-PL011-UARTs-are-actually-r1p5.patch | 43 + ...ts-rp1-PL011-UARTs-are-actually-r1p5.patch | 70 + ...cm512x-Demote-No-SCLK-to-debug-level.patch | 25 + ...o-piano-dac-plus-Fix-volume-limiting.patch | 58 + ...piano-dac-plus-Remove-pointless-code.patch | 53 + ...2712-override-supports-cqe-to-a-cell.patch | 90 + ...rd-CQ-support-based-on-an-allow-list.patch | 57 + ...K_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch | 41 + ...am-DT-property-to-modify-CQE-and-or-.patch | 94 + ...509-misc-rp1-pio-Handle-probe-errors.patch | 38 + ...rmware-rp1-Simplify-rp1_firmware_get.patch | 84 + ...1-Don-t-mark-timer-regs-unconfigured.patch | 44 + ...-sdhost-Observe-SWIOTLB-memory-limit.patch | 29 + ...sp_be-Add-support-for-YUV422-planar-.patch | 31 + ...sp_be-Remove-unused-fields-in-struct.patch | 82 + ...ust-PLL-settings-based-on-the-number.patch | 163 ++ ...ne-option-to-the-device-tree-overlay.patch | 55 + ...hare-panel-Disable-new-touch-control.patch | 40 + ...Add-rgb_order-property-to-match-VC4-.patch | 325 +++ .../950-1522-add-ina238-to-i2c-sensors.patch | 102 + .../950-1524-add-shtc3-to-i2c-sensors.patch | 57 + ...i-Update-Hailo-accelerator-device-dr.patch | 2137 +++++++++++++++++ ...lays-Regularisation-and-improvements.patch | 139 ++ ...tor-out-the-common-i2c-bus-selection.patch | 1630 +++++++++++++ ...pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch | 63 + ...0-1530-spi-dw-Wait-for-idle-after-TX.patch | 29 + ...o-Error-out-on-incompatible-firmware.patch | 42 + ...mware-rp1-Linger-on-firmware-failure.patch | 103 + ...rp1-Don-t-claim-channels-in-of_xlate.patch | 30 + ...-fixup-spi-dw-Wait-for-idle-after-TX.patch | 25 + ...support-for-Hifiberry-ADC8x-to-the-D.patch | 76 + ...ADC8x-support-to-the-Hifiberry-DAC8x.patch | 75 + ...c3-Set-DMA-and-coherent-masks-early.patch} | 67 +- ...d-OpenHydroponics-RootMaster-overlay.patch | 119 + ...m-pivariety-Fix-mutex-init-and-NULL-.patch | 37 + ...pio-Demote-fw-probe-error-to-warning.patch | 32 + ...s-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch | 38 + ...gpio-bridge-fix-gpiod-error-handling.patch | 25 + ...-gpio-bridge-probe-Cfg-fast_xfer-clk.patch | 37 + ...950-1547-fix-clang-compilation-error.patch | 30 + .../950-1548-delete-the-comment.patch | 22 + ...1-Add-continuous-clock-option-as-an-.patch | 66 + .../950-1550-drm-v3d-Add-clock-handling.patch | 129 + ...n-jobs-that-have-errors-flagged-in-i.patch | 61 + ...pointer-to-NULL-when-the-job-s-fence.patch | 84 + ...e-a-V3D-tech-revision-to-all-support.patch | 447 ++++ ...pu-v3d-Add-SMS-to-the-registers-list.patch | 43 + ...SMS-registers-for-power-on-off-and-r.patch | 198 ++ ...556-dts-bcm2712-Add-V3D_SMS-register.patch | 27 + ...ove-the-power-key-debounce-on-Pi-500.patch | 21 + 64 files changed, 9054 insertions(+), 64 deletions(-) create mode 100644 target/linux/bcm27xx/patches-6.6/950-1484-Add-and-update-files-for-pwm-gpio-fan-overlay.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1486-media-i2c-imx290-Limit-analogue-gain-according-to-mo.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1488-media-dt-bindings-sony-imx290-Add-IMX462-to-the-IMX2.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1489-media-i2c-imx290-Add-configuration-for-IMX462.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1490-media-imx290-Add-module-parameter-to-allow-selection.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1491-dtoverlays-Switch-imx462-overlay-to-use-the-new-comp.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1492-media-i2c-imx415-Add-more-clock-configurations.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1494-dtoverlays-Add-overlay-for-Sony-IMX415-image-sensor.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1495-media-i2c-imx415-Add-read-write-control-of-VBLANK.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1496-media-i2c-imx415-Make-HBLANK-controllable-and-in-con.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1497-media-i2c-imx415-Link-frequencies-are-not-exclusive-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1498-dts-bcm2711-PL011-UARTs-are-actually-r1p5.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1499-dts-bcm2712-PL011-UARTs-are-actually-r1p5.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1500-dts-rp1-PL011-UARTs-are-actually-r1p5.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1501-ASoC-pcm512x-Demote-No-SCLK-to-debug-level.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1502-ASoC-allo-piano-dac-plus-Fix-volume-limiting.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1503-ASoC-allo-piano-dac-plus-Remove-pointless-code.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1505-DT-bcm2712-override-supports-cqe-to-a-cell.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1506-mmc-sd-filter-card-CQ-support-based-on-an-allow-list.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1507-mmc-set-MMC_QUIRK_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1508-mmc-use-downstream-DT-property-to-modify-CQE-and-or-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1509-misc-rp1-pio-Handle-probe-errors.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1510-firmware-rp1-Simplify-rp1_firmware_get.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1512-dts-bcm2711-Don-t-mark-timer-regs-unconfigured.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1513-mmc-bcm2835-sdhost-Observe-SWIOTLB-memory-limit.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1514-drivers-media-pisp_be-Add-support-for-YUV422-planar-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1515-drivers-media-pisp_be-Remove-unused-fields-in-struct.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1516-media-imx219-Adjust-PLL-settings-based-on-the-number.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1517-IMX219-Add-4-lane-option-to-the-device-tree-overlay.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1518-dtoverlays-waveshare-panel-Disable-new-touch-control.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1522-add-ina238-to-i2c-sensors.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1524-add-shtc3-to-i2c-sensors.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1525-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1526-overlays-Regularisation-and-improvements.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1527-overlays-Factor-out-the-common-i2c-bus-selection.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1529-misc-rp1-pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1530-spi-dw-Wait-for-idle-after-TX.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1531-misc-rp1-pio-Error-out-on-incompatible-firmware.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1532-firmware-rp1-Linger-on-firmware-failure.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1533-mailbox-rp1-Don-t-claim-channels-in-of_xlate.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1534-fixup-spi-dw-Wait-for-idle-after-TX.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1535-dtoverlays-adds-support-for-Hifiberry-ADC8x-to-the-D.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1536-ASoC-adds-ADC8x-support-to-the-Hifiberry-DAC8x.patch rename target/linux/bcm27xx/patches-6.6/{950-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch => 950-1539-Reapply-usb-dwc3-Set-DMA-and-coherent-masks-early.patch} (81%) create mode 100644 target/linux/bcm27xx/patches-6.6/950-1541-overlays-Add-OpenHydroponics-RootMaster-overlay.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1542-media-i2c-arducam-pivariety-Fix-mutex-init-and-NULL-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1543-misc-rp1-pio-Demote-fw-probe-error-to-warning.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1544-dts-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1545-spi-rp2040-gpio-bridge-fix-gpiod-error-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1546-spi-rp2040-gpio-bridge-probe-Cfg-fast_xfer-clk.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1547-fix-clang-compilation-error.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1548-delete-the-comment.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1549-dtoverlays-ov9281-Add-continuous-clock-option-as-an-.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1550-drm-v3d-Add-clock-handling.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1551-drm-v3d-Don-t-run-jobs-that-have-errors-flagged-in-i.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1552-drm-v3d-Set-job-pointer-to-NULL-when-the-job-s-fence.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1553-drm-v3d-Associate-a-V3D-tech-revision-to-all-support.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1554-dt-bindings-gpu-v3d-Add-SMS-to-the-registers-list.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1555-drm-v3d-Use-V3D_SMS-registers-for-power-on-off-and-r.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1556-dts-bcm2712-Add-V3D_SMS-register.patch create mode 100644 target/linux/bcm27xx/patches-6.6/950-1557-dts-Remove-the-power-key-debounce-on-Pi-500.patch diff --git a/target/linux/bcm27xx/patches-6.6/950-0853-drivers-usb-dwc3-add-FS-LS-bus-instance-parkmode-dis.patch b/target/linux/bcm27xx/patches-6.6/950-0853-drivers-usb-dwc3-add-FS-LS-bus-instance-parkmode-dis.patch index 47fa0b75416..77aebef467c 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0853-drivers-usb-dwc3-add-FS-LS-bus-instance-parkmode-dis.patch +++ b/target/linux/bcm27xx/patches-6.6/950-0853-drivers-usb-dwc3-add-FS-LS-bus-instance-parkmode-dis.patch @@ -16,7 +16,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c -@@ -1387,6 +1387,9 @@ static int dwc3_core_init(struct dwc3 *d +@@ -1367,6 +1367,9 @@ static int dwc3_core_init(struct dwc3 *d if (dwc->parkmode_disable_hs_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; @@ -26,7 +26,7 @@ Signed-off-by: Jonathan Bell if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && (dwc->maximum_speed == USB_SPEED_HIGH || dwc->maximum_speed == USB_SPEED_FULL)) -@@ -1676,6 +1679,8 @@ static void dwc3_get_properties(struct d +@@ -1634,6 +1637,8 @@ static void dwc3_get_properties(struct d "snps,parkmode-disable-ss-quirk"); dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, "snps,parkmode-disable-hs-quirk"); @@ -37,7 +37,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h -@@ -271,6 +271,7 @@ +@@ -268,6 +268,7 @@ #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) @@ -45,7 +45,7 @@ Signed-off-by: Jonathan Bell #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ -@@ -1122,10 +1123,12 @@ struct dwc3_scratchpad_array { +@@ -1118,10 +1119,12 @@ struct dwc3_scratchpad_array { * generation after resume from suspend. * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin * VBUS with an external supply. @@ -62,7 +62,7 @@ Signed-off-by: Jonathan Bell * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis -@@ -1352,6 +1355,7 @@ struct dwc3 { +@@ -1347,6 +1350,7 @@ struct dwc3 { unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; unsigned parkmode_disable_hs_quirk:1; diff --git a/target/linux/bcm27xx/patches-6.6/950-1359-usb-dwc3-core-add-support-for-setting-NAK-enhancemen.patch b/target/linux/bcm27xx/patches-6.6/950-1359-usb-dwc3-core-add-support-for-setting-NAK-enhancemen.patch index 5b700990b27..db0cce8d59d 100644 --- a/target/linux/bcm27xx/patches-6.6/950-1359-usb-dwc3-core-add-support-for-setting-NAK-enhancemen.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1359-usb-dwc3-core-add-support-for-setting-NAK-enhancemen.patch @@ -22,7 +22,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c -@@ -1381,6 +1381,12 @@ static int dwc3_core_init(struct dwc3 *d +@@ -1361,6 +1361,12 @@ static int dwc3_core_init(struct dwc3 *d if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; @@ -35,7 +35,7 @@ Signed-off-by: Jonathan Bell if (dwc->parkmode_disable_ss_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; -@@ -1675,6 +1681,10 @@ static void dwc3_get_properties(struct d +@@ -1633,6 +1639,10 @@ static void dwc3_get_properties(struct d "snps,resume-hs-terminations"); dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev, "snps,ulpi-ext-vbus-drv"); @@ -48,7 +48,7 @@ Signed-off-by: Jonathan Bell dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h -@@ -269,6 +269,8 @@ +@@ -266,6 +266,8 @@ #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) @@ -57,7 +57,7 @@ Signed-off-by: Jonathan Bell #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) #define DWC3_GUCTL1_PARKMODE_DISABLE_FSLS BIT(15) -@@ -1123,6 +1125,8 @@ struct dwc3_scratchpad_array { +@@ -1119,6 +1121,8 @@ struct dwc3_scratchpad_array { * generation after resume from suspend. * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin * VBUS with an external supply. @@ -66,7 +66,7 @@ Signed-off-by: Jonathan Bell * @parkmode_disable_ss_quirk: If set, disable park mode feature for all * Superspeed instances. * @parkmode_disable_hs_quirk: If set, disable park mode feature for all -@@ -1353,6 +1357,8 @@ struct dwc3 { +@@ -1348,6 +1352,8 @@ struct dwc3 { unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned resume_hs_terminations:1; unsigned ulpi_ext_vbus_drv:1; diff --git a/target/linux/bcm27xx/patches-6.6/950-1484-Add-and-update-files-for-pwm-gpio-fan-overlay.patch b/target/linux/bcm27xx/patches-6.6/950-1484-Add-and-update-files-for-pwm-gpio-fan-overlay.patch new file mode 100644 index 00000000000..521b3407303 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1484-Add-and-update-files-for-pwm-gpio-fan-overlay.patch @@ -0,0 +1,246 @@ +From 5fa4b1ff4db7635da04b1b8bf33b42a941064718 Mon Sep 17 00:00:00 2001 +From: Kai-Uwe Herbing <155751635+herbingk@users.noreply.github.com> +Date: Tue, 31 Dec 2024 19:44:31 +0100 +Subject: [PATCH] Add and update files for pwm-gpio-fan overlay + +Add and update files for pwm-gpio-fan overlay +Signed-off-by: Kai-Uwe Herbing <155751635+herbingk@users.noreply.github.com> +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 40 +++++ + .../dts/overlays/pwm-gpio-fan-overlay.dts | 170 ++++++++++++++++++ + 3 files changed, 211 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/pwm-gpio-fan-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -219,6 +219,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + pwm.dtbo \ + pwm-2chan.dtbo \ + pwm-gpio.dtbo \ ++ pwm-gpio-fan.dtbo \ + pwm-ir-tx.dtbo \ + pwm-pio.dtbo \ + pwm1.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -4036,6 +4036,46 @@ Load: dtoverlay=pwm-gpio,= + Params: gpio Output pin (default 4) + + ++Name: pwm-gpio-fan ++Info: Configure a GPIO connected PWM cooling fan controlled by the ++ software-based GPIO PWM kernel module ++Load: dtoverlay=pwm-gpio-fan,= ++Params: fan_gpio BCM number of the pin driving the fan, ++ default 18 (GPIO 18) ++ fan_temp0 CPU temperature at which fan is started with ++ low speed in millicelsius, ++ default 55000 (55 °C) ++ fan_temp1 CPU temperature at which fan is switched ++ to medium speed in millicelsius, ++ default 60000 (60 °C) ++ fan_temp2 CPU temperature at which fan is switched ++ to high speed in millicelsius, ++ default 67500 (67.5 °C) ++ fan_temp3 CPU temperature at which fan is switched ++ to max speed in millicelsius, ++ default 75000 (75 °C) ++ fan_temp0_hyst Temperature hysteris at which fan is stopped ++ in millicelsius,default 5000 (resulting ++ in 50 °C) ++ fan_temp1_hyst Temperature hysteris at which fan is switched ++ back to low speed in millicelsius, ++ default 5000 (resulting in 55 °C) ++ fan_temp2_hyst Temperature hysteris at which fan is switched ++ back to medium speed in millicelsius, ++ default 5000 (resulting in 62.5 °C) ++ fan_temp3_hyst Temperature hysteris at which fan is switched ++ back to high speed in millicelsius, ++ default 5000 (resulting in 70 °C) ++ fan_temp0_speed Fan speed for low cooling state in range ++ 0 to 255, default 114 (45% PWM duty cycle) ++ fan_temp1_speed Fan speed for medium cooling state in range ++ 0 to 255, default 152 (60% PWM duty cycle) ++ fan_temp2_speed Fan speed for high cooling state in range ++ 0 to 255, default 204 (80% PWM duty cycle) ++ fan_temp3_speed Fan speed for max cooling state in range ++ 0 to 255, default 255 (100% PWM duty cycle) ++ ++ + Name: pwm-ir-tx + Info: Use GPIO pin as pwm-assisted infrared transmitter output. + This is an alternative to "gpio-ir-tx". pwm-ir-tx makes use +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/pwm-gpio-fan-overlay.dts +@@ -0,0 +1,170 @@ ++/* ++ * Overlay for a GPIO connected PWM cooling fan controlled by software GPIO PWM ++ * ++ * Optional parameters: ++ * - "fan_gpio" BCM number of the pin driving the fan, default 18 (GPIO18) ++ * ++ * - "fan_temp0" CPU temperature at which fan is started with low speed in millicelsius, ++ * default 55000 (55 °C) ++ * - "fan_temp1" CPU temperature at which fan is switched to medium speed in millicelsius, ++ * default 60000 (60 °C) ++ * - "fan_temp2" CPU temperature at which fan is switched to high speed in millicelsius, ++ * default 67500 (67.5 °C) ++ * - "fan_temp3" CPU temperature at which fan is switched to max speed in millicelsius, ++ * default 75000 (75 °C) ++ * - "fan_temp0_hyst" Temperature hysteris at which fan is stopped in millicelsius, ++ * default 5000 (resulting in 50 °C) ++ * - "fan_temp1_hyst" Temperature hysteris at which fan is switched back to low speed ++ * in millicelsius, default 5000 (resulting in 55 °C) ++ * - "fan_temp2_hyst" Temperature hysteris at which fan is switched back to medium speed ++ * in millicelsius, default 5000 (resulting in 62.5 °C) ++ * - "fan_temp3_hyst" Temperature hysteris at which fan is switched back to high speed ++ * in millicelsius, default 5000 (resulting in 70 °C) ++ * - "fan_temp0_speed" Fan speed for low cooling state in range 0 to 255, ++ * default 114 (45% PWM duty cycle) ++ * - "fan_temp1_speed" Fan speed for medium cooling state in range 0 to 255, ++ * default 152 (60% PWM duty cycle) ++ * - "fan_temp2_speed" Fan speed for high cooling state in range 0 to 255, ++ * default 204 (80% PWM duty cycle) ++ * - "fan_temp3_speed" Fan speed for max cooling state in range 0 to 255, ++ * default 255 (100% PWM duty cycle) ++ * ++ * N.B. ++ * - Uses the software GPIO PWM kernel module instead of the Pis hardware PWMs (PWM0/PWM1). ++ * This will allow for an undisturbed concurrent usage of the Pis analogue audio output. ++ * ++ * Requires: ++ * - A PWM controlled cooling fan connected to the GPIO, such as an ++ * Argon mini-fan, HighPi Pro Fan or Waveshare FAN-4020-PWM-5V ++ * - Raspberry Pi OS Bookworm with kernel 6.6.62 or above ++ * ++ * Build: ++ * - sudo dtc -I dts -O dtb -o /boot/firmware/overlays/pwm-gpiofan.dtbo pwm-gpiofan-overlay.dts ++ * ++ * Activate: ++ * - sudo nano /boot/firmware/config.txt add "dtoverlay=pwm-gpiofan" ++ * ++ */ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&gpio>; ++ __overlay__ { ++ pwm_gpio_pins: pwm_gpio_pins { ++ brcm,pins = <18>; /* gpio-pin = 18 */ ++ brcm,function = <1>; /* gpio function = output */ ++ brcm,pull = <0>; /* gpio pull up/down = off */ ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ pwm_gpio: pwm_gpio { ++ compatible="pwm-gpio"; ++ #pwm-cells = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_gpio_pins>; ++ gpios = <&gpio 18 0>; /* gpio-pin = 18 */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ fan0: pwm-fan { ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ /* in ns = 20ms = 50 Hz */ ++ pwms = <&pwm_gpio 0 20000000 0>; ++ ++ cooling-min-state = <0>; ++ cooling-max-state = <4>; ++ /* PWM duty cycle values in a range from 0 to 255 */ ++ /* which correspond to thermal cooling states 0 to 4 */ ++ cooling-levels = <0 114 152 204 255>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&cpu_thermal>; ++ __overlay__ { ++ /* in ms = poll every 2s */ ++ polling-delay = <2000>; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&thermal_trips>; ++ __overlay__ { ++ /* below temperatures in millicelsius */ ++ trip0: trip0 { ++ temperature = <55000>; /* 55 °C */ ++ hysteresis = <5000>; /* 5 °C */ ++ type = "active"; ++ }; ++ trip1: trip1 { ++ temperature = <60000>; /* 60 °C */ ++ hysteresis = <5000>; /* 5 °C */ ++ type = "active"; ++ }; ++ trip2: trip2 { ++ temperature = <67500>; /* 67.5 °C */ ++ hysteresis = <5000>; /* 5 °C */ ++ type = "active"; ++ }; ++ trip3: trip3 { ++ temperature = <75000>; /* 75 °C */ ++ hysteresis = <5000>; /* 5 °C */ ++ type = "active"; ++ }; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&cooling_maps>; ++ __overlay__ { ++ map0 { ++ cooling-device = <&fan0 0 1>; ++ trip = <&trip0>; ++ }; ++ map1 { ++ cooling-device = <&fan0 1 2>; ++ trip = <&trip1>; ++ }; ++ map2 { ++ cooling-device = <&fan0 2 3>; ++ trip = <&trip2>; ++ }; ++ map3 { ++ cooling-device = <&fan0 3 4>; ++ trip = <&trip3>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ fan_gpio = <&pwm_gpio>,"gpios:4", ++ <&pwm_gpio_pins>,"brcm,pins:0"; ++ fan_temp0 = <&trip0>,"temperature:0"; ++ fan_temp0_hyst = <&trip0>,"hysteresis:0"; ++ fan_temp0_speed = <&fan0>,"cooling-levels:4"; ++ fan_temp1 = <&trip1>,"temperature:0"; ++ fan_temp1_hyst = <&trip1>,"hysteresis:0"; ++ fan_temp1_speed = <&fan0>,"cooling-levels:8"; ++ fan_temp2 = <&trip2>,"temperature:0"; ++ fan_temp2_hyst = <&trip2>,"hysteresis:0"; ++ fan_temp2_speed = <&fan0>,"cooling-levels:12"; ++ fan_temp3 = <&trip3>,"temperature:0"; ++ fan_temp3_hyst = <&trip3>,"hysteresis:0"; ++ fan_temp3_speed = <&fan0>,"cooling-levels:16"; ++ }; ++ ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1486-media-i2c-imx290-Limit-analogue-gain-according-to-mo.patch b/target/linux/bcm27xx/patches-6.6/950-1486-media-i2c-imx290-Limit-analogue-gain-according-to-mo.patch new file mode 100644 index 00000000000..818f95f7c3b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1486-media-i2c-imx290-Limit-analogue-gain-according-to-mo.patch @@ -0,0 +1,71 @@ +From b3dd7e8947cddec41864e8d3ce5f5d8b81033d6a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 20 Nov 2024 19:17:03 +0000 +Subject: [PATCH] media: i2c: imx290: Limit analogue gain according to module + +Commit ec75fd952b0b5cdab7b606cdacba237c57c1fdda upstream. + +The imx327 only supports up to 29.4dB of analogue gain, vs +the imx290 going up to 30dB. Both are in 0.3dB steps. + +As we now have model specific config, fix this mismatch, +and delete the comment referencing it. + +Signed-off-by: Dave Stevenson +Reviewed-by: Laurent Pinchart +Reviewed-by: Alexander Stein +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/imx290.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -178,6 +178,7 @@ struct imx290_model_info { + enum imx290_colour_variant colour_variant; + const struct cci_reg_sequence *init_regs; + size_t init_regs_num; ++ unsigned int max_analog_gain; + const char *name; + }; + +@@ -879,14 +880,10 @@ static int imx290_ctrl_init(struct imx29 + * up to 72.0dB (240) add further digital gain. Limit the range to + * analog gain only, support for digital gain can be added separately + * if needed. +- * +- * The IMX327 and IMX462 are largely compatible with the IMX290, but +- * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital +- * gain. When support for those sensors gets added to the driver, the +- * gain control should be adjusted accordingly. + */ + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, +- V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); ++ V4L2_CID_ANALOGUE_GAIN, 0, ++ imx290->model->max_analog_gain, 1, 0); + + /* + * Correct range will be determined through imx290_ctrl_update setting +@@ -1437,18 +1434,21 @@ static const struct imx290_model_info im + .colour_variant = IMX290_VARIANT_COLOUR, + .init_regs = imx290_global_init_settings_290, + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290), ++ .max_analog_gain = 100, + .name = "imx290", + }, + [IMX290_MODEL_IMX290LLR] = { + .colour_variant = IMX290_VARIANT_MONO, + .init_regs = imx290_global_init_settings_290, + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290), ++ .max_analog_gain = 100, + .name = "imx290", + }, + [IMX290_MODEL_IMX327LQR] = { + .colour_variant = IMX290_VARIANT_COLOUR, + .init_regs = imx290_global_init_settings_327, + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_327), ++ .max_analog_gain = 98, + .name = "imx327", + }, + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1488-media-dt-bindings-sony-imx290-Add-IMX462-to-the-IMX2.patch b/target/linux/bcm27xx/patches-6.6/950-1488-media-dt-bindings-sony-imx290-Add-IMX462-to-the-IMX2.patch new file mode 100644 index 00000000000..7cf477c3c8e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1488-media-dt-bindings-sony-imx290-Add-IMX462-to-the-IMX2.patch @@ -0,0 +1,31 @@ +From f4f17c3fe223b3d8ad65f5420abbcd69ef901186 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 20 Nov 2024 19:17:05 +0000 +Subject: [PATCH] media: dt-bindings: sony,imx290: Add IMX462 to the IMX290 + binding + +Commit e4faac99d5bb4b6c80f2495c40fcd71a67c40b27 upstream. + +IMX462 is the successor to IMX290, which is supportable by +the existing IMX290 driver via a new compatible string. + +Signed-off-by: Dave Stevenson +Acked-by: Conor Dooley +Reviewed-by: Laurent Pinchart +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml +@@ -30,6 +30,8 @@ properties: + - sony,imx290lqr # Colour + - sony,imx290llr # Monochrome + - sony,imx327lqr # Colour ++ - sony,imx462lqr # Colour ++ - sony,imx462llr # Monochrome + - const: sony,imx290 + deprecated: true + diff --git a/target/linux/bcm27xx/patches-6.6/950-1489-media-i2c-imx290-Add-configuration-for-IMX462.patch b/target/linux/bcm27xx/patches-6.6/950-1489-media-i2c-imx290-Add-configuration-for-IMX462.patch new file mode 100644 index 00000000000..027f4571d81 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1489-media-i2c-imx290-Add-configuration-for-IMX462.patch @@ -0,0 +1,116 @@ +From 23037697914a6d1220768a752c6358d35ca03737 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 20 Nov 2024 19:17:06 +0000 +Subject: [PATCH] media: i2c: imx290: Add configuration for IMX462 + +Commit c699b6c7c857baba1375a1ed090bf71f695e2971 upstream. + +IMX462 is the successor to IMX290, and wants very minor +changes to the register setup. + +Add the relevant configuration to support it. + +Signed-off-by: Dave Stevenson +Reviewed-by: Laurent Pinchart +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/imx290.c | 66 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -172,6 +172,8 @@ enum imx290_model { + IMX290_MODEL_IMX290LQR, + IMX290_MODEL_IMX290LLR, + IMX290_MODEL_IMX327LQR, ++ IMX290_MODEL_IMX462LQR, ++ IMX290_MODEL_IMX462LLR, + }; + + struct imx290_model_info { +@@ -318,6 +320,50 @@ static const struct cci_reg_sequence imx + { CCI_REG8(0x33b3), 0x04 }, + }; + ++static const struct cci_reg_sequence imx290_global_init_settings_462[] = { ++ { CCI_REG8(0x300f), 0x00 }, ++ { CCI_REG8(0x3010), 0x21 }, ++ { CCI_REG8(0x3011), 0x02 }, ++ { CCI_REG8(0x3016), 0x09 }, ++ { CCI_REG8(0x3070), 0x02 }, ++ { CCI_REG8(0x3071), 0x11 }, ++ { CCI_REG8(0x309b), 0x10 }, ++ { CCI_REG8(0x309c), 0x22 }, ++ { CCI_REG8(0x30a2), 0x02 }, ++ { CCI_REG8(0x30a6), 0x20 }, ++ { CCI_REG8(0x30a8), 0x20 }, ++ { CCI_REG8(0x30aa), 0x20 }, ++ { CCI_REG8(0x30ac), 0x20 }, ++ { CCI_REG8(0x30b0), 0x43 }, ++ { CCI_REG8(0x3119), 0x9e }, ++ { CCI_REG8(0x311c), 0x1e }, ++ { CCI_REG8(0x311e), 0x08 }, ++ { CCI_REG8(0x3128), 0x05 }, ++ { CCI_REG8(0x313d), 0x83 }, ++ { CCI_REG8(0x3150), 0x03 }, ++ { CCI_REG8(0x317e), 0x00 }, ++ { CCI_REG8(0x32b8), 0x50 }, ++ { CCI_REG8(0x32b9), 0x10 }, ++ { CCI_REG8(0x32ba), 0x00 }, ++ { CCI_REG8(0x32bb), 0x04 }, ++ { CCI_REG8(0x32c8), 0x50 }, ++ { CCI_REG8(0x32c9), 0x10 }, ++ { CCI_REG8(0x32ca), 0x00 }, ++ { CCI_REG8(0x32cb), 0x04 }, ++ { CCI_REG8(0x332c), 0xd3 }, ++ { CCI_REG8(0x332d), 0x10 }, ++ { CCI_REG8(0x332e), 0x0d }, ++ { CCI_REG8(0x3358), 0x06 }, ++ { CCI_REG8(0x3359), 0xe1 }, ++ { CCI_REG8(0x335a), 0x11 }, ++ { CCI_REG8(0x3360), 0x1e }, ++ { CCI_REG8(0x3361), 0x61 }, ++ { CCI_REG8(0x3362), 0x10 }, ++ { CCI_REG8(0x33b0), 0x50 }, ++ { CCI_REG8(0x33b2), 0x1a }, ++ { CCI_REG8(0x33b3), 0x04 }, ++}; ++ + #define IMX290_NUM_CLK_REGS 2 + static const struct cci_reg_sequence xclk_regs[][IMX290_NUM_CLK_REGS] = { + [IMX290_CLK_37_125] = { +@@ -1451,6 +1497,20 @@ static const struct imx290_model_info im + .max_analog_gain = 98, + .name = "imx327", + }, ++ [IMX290_MODEL_IMX462LQR] = { ++ .colour_variant = IMX290_VARIANT_COLOUR, ++ .init_regs = imx290_global_init_settings_462, ++ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462), ++ .max_analog_gain = 98, ++ .name = "imx462", ++ }, ++ [IMX290_MODEL_IMX462LLR] = { ++ .colour_variant = IMX290_VARIANT_MONO, ++ .init_regs = imx290_global_init_settings_462, ++ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462), ++ .max_analog_gain = 98, ++ .name = "imx462", ++ }, + }; + + static int imx290_parse_dt(struct imx290 *imx290) +@@ -1646,6 +1706,12 @@ static const struct of_device_id imx290_ + }, { + .compatible = "sony,imx327lqr", + .data = &imx290_models[IMX290_MODEL_IMX327LQR], ++ }, { ++ .compatible = "sony,imx462lqr", ++ .data = &imx290_models[IMX290_MODEL_IMX462LQR], ++ }, { ++ .compatible = "sony,imx462llr", ++ .data = &imx290_models[IMX290_MODEL_IMX462LLR], + }, + { /* sentinel */ }, + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1490-media-imx290-Add-module-parameter-to-allow-selection.patch b/target/linux/bcm27xx/patches-6.6/950-1490-media-imx290-Add-module-parameter-to-allow-selection.patch new file mode 100644 index 00000000000..219cfce67be --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1490-media-imx290-Add-module-parameter-to-allow-selection.patch @@ -0,0 +1,60 @@ +From c633c2e93e460925120e0817c14bbfc444a70226 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 15 May 2024 12:43:15 +0100 +Subject: [PATCH] media: imx290: Add module parameter to allow selection of HCG + mode + +The sensor has Low Conversion Gain (HCG) and High Conversion Gain (HCG) +modes, with the supposedly the HCG mode having better noise performance +at high gains. + +As this parameter changes the gain range of the sensor, it isn't +possible to make this an automatic property, and there is no +suitable V4L2 control to set it, so just add it as a module parameter. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/imx290.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,9 @@ + #define IMX290_WINMODE_720P (1 << 4) + #define IMX290_WINMODE_CROP (4 << 4) + #define IMX290_FR_FDG_SEL CCI_REG8(0x3009) ++#define IMX290_FDG_HCG BIT(4) ++#define IMX290_FRSEL_60FPS BIT(0) ++#define IMX290_FDG_LCG 0 + #define IMX290_BLKLEVEL CCI_REG16_LE(0x300a) + #define IMX290_GAIN CCI_REG8(0x3014) + #define IMX290_VMAX CCI_REG24_LE(0x3018) +@@ -162,6 +166,10 @@ + + #define IMX290_NUM_SUPPLIES 3 + ++static bool hcg_mode; ++module_param(hcg_mode, bool, 0664); ++MODULE_PARM_DESC(hcg_mode, "Enable HCG mode"); ++ + enum imx290_colour_variant { + IMX290_VARIANT_COLOUR, + IMX290_VARIANT_MONO, +@@ -697,7 +705,8 @@ static int imx290_set_data_lanes(struct + &ret); + cci_write(imx290->regmap, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, + &ret); +- cci_write(imx290->regmap, IMX290_FR_FDG_SEL, 0x01, &ret); ++ cci_write(imx290->regmap, IMX290_FR_FDG_SEL, IMX290_FRSEL_60FPS | ++ (hcg_mode ? IMX290_FDG_HCG : IMX290_FDG_LCG), &ret); + + return ret; + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1491-dtoverlays-Switch-imx462-overlay-to-use-the-new-comp.patch b/target/linux/bcm27xx/patches-6.6/950-1491-dtoverlays-Switch-imx462-overlay-to-use-the-new-comp.patch new file mode 100644 index 00000000000..8e894791c23 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1491-dtoverlays-Switch-imx462-overlay-to-use-the-new-comp.patch @@ -0,0 +1,47 @@ +From eec7048c4e3aec1aadc21fcffcf6be9f5385f72a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 12 Nov 2024 14:15:30 +0000 +Subject: [PATCH] dtoverlays: Switch imx462 overlay to use the new compatible + +Now that imx462 has a separate compatible string, make use of it. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/imx462-overlay.dts | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +--- a/arch/arm/boot/dts/overlays/imx462-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx462-overlay.dts +@@ -1,9 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-only + // Definitions for IMX462 camera module on VC I2C bus + +-// IMX462 is the successor to IMX290. The drivers currently don't support +-// any additional feature of IMX462, so use the IMX290 compatible strings +-// for now. ++// IMX462 is the successor to IMX290. + + /dts-v1/; + /plugin/; +@@ -17,19 +15,17 @@ + // Fragment numbers deliberately high to avoid conflicts with the + // included imx290_327 overlay file. + +- //IMX462 is not defined in the bindings, so use IMX290 for now. +- + fragment@101 { + target = <&cam_node>; + __overlay__ { +- compatible = "sony,imx290lqr"; ++ compatible = "sony,imx462lqr"; + }; + }; + + fragment@102 { + target = <&cam_node>; + __dormant__ { +- compatible = "sony,imx290llr"; ++ compatible = "sony,imx462llr"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1492-media-i2c-imx415-Add-more-clock-configurations.patch b/target/linux/bcm27xx/patches-6.6/950-1492-media-i2c-imx415-Add-more-clock-configurations.patch new file mode 100644 index 00000000000..0b04bf0c2b2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1492-media-i2c-imx415-Add-more-clock-configurations.patch @@ -0,0 +1,327 @@ +From 0a0814f830829b1a377273ddb09c156c84e1a8ca Mon Sep 17 00:00:00 2001 +From: Alexander Stein +Date: Wed, 17 Jan 2024 08:39:36 +0100 +Subject: [PATCH] media: i2c: imx415: Add more clock configurations + +Commit b814b5b2ec2d327b79e415c1baa5eecdf9aa786b upstream. + +Complete the list from "INCK Setting" section in IMX415-AAQR-C +(Rev. E19504, 2019/05/21). For consistency suffix all lane rate values by +UL, which is needed for 2376000000 anyway. + +Signed-off-by: Alexander Stein +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/imx415.c | 265 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 260 insertions(+), 5 deletions(-) + +--- a/drivers/media/i2c/imx415.c ++++ b/drivers/media/i2c/imx415.c +@@ -124,7 +124,7 @@ struct imx415_clk_params { + /* INCK Settings - includes all lane rate and INCK dependent registers */ + static const struct imx415_clk_params imx415_clk_params[] = { + { +- .lane_rate = 594000000, ++ .lane_rate = 594000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, +@@ -139,7 +139,37 @@ static const struct imx415_clk_params im + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { +- .lane_rate = 720000000, ++ .lane_rate = 594000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x7 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x080 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x0 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x1 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0984 }, ++ }, ++ { ++ .lane_rate = 594000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x7 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x080 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x0 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x1 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, ++ { ++ .lane_rate = 720000000UL, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, +@@ -154,7 +184,22 @@ static const struct imx415_clk_params im + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { +- .lane_rate = 891000000, ++ .lane_rate = 720000000UL, ++ .inck = 72000000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x9 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x0 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x1 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, ++ }, ++ { ++ .lane_rate = 891000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, +@@ -169,7 +214,37 @@ static const struct imx415_clk_params im + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { +- .lane_rate = 1440000000, ++ .lane_rate = 891000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x5 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x0 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x1 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, ++ }, ++ { ++ .lane_rate = 891000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x5 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x0 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x1 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, ++ { ++ .lane_rate = 1440000000UL, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, +@@ -184,7 +259,22 @@ static const struct imx415_clk_params im + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { +- .lane_rate = 1485000000, ++ .lane_rate = 1440000000UL, ++ .inck = 72000000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x8 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, ++ }, ++ { ++ .lane_rate = 1485000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, +@@ -198,6 +288,171 @@ static const struct imx415_clk_params im + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, ++ { ++ .lane_rate = 1485000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x8 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, ++ }, ++ { ++ .lane_rate = 1485000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x8 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, ++ { ++ .lane_rate = 1782000000UL, ++ .inck = 27000000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x4 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x23 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0C6 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x23 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, ++ }, ++ { ++ .lane_rate = 1782000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x4 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, ++ }, ++ { ++ .lane_rate = 1782000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x4 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, ++ { ++ .lane_rate = 2079000000UL, ++ .inck = 27000000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x2 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x23 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0E7 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x23 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, ++ }, ++ { ++ .lane_rate = 2079000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x2 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, ++ }, ++ { ++ .lane_rate = 2079000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x2 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, ++ { ++ .lane_rate = 2376000000UL, ++ .inck = 27000000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x0 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x23 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x108 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x23 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, ++ }, ++ { ++ .lane_rate = 2376000000UL, ++ .inck = 37125000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, ++ .regs[2] = { IMX415_SYS_MODE, 0x0 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x24 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x100 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x24 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, ++ }, ++ { ++ .lane_rate = 2376000000UL, ++ .inck = 74250000, ++ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, ++ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, ++ .regs[2] = { IMX415_SYS_MODE, 0x0 }, ++ .regs[3] = { IMX415_INCKSEL1, 0x00 }, ++ .regs[4] = { IMX415_INCKSEL2, 0x28 }, ++ .regs[5] = { IMX415_INCKSEL3, 0x100 }, ++ .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, ++ .regs[7] = { IMX415_INCKSEL5, 0x28 }, ++ .regs[8] = { IMX415_INCKSEL6, 0x1 }, ++ .regs[9] = { IMX415_INCKSEL7, 0x0 }, ++ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, ++ }, + }; + + /* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1494-dtoverlays-Add-overlay-for-Sony-IMX415-image-sensor.patch b/target/linux/bcm27xx/patches-6.6/950-1494-dtoverlays-Add-overlay-for-Sony-IMX415-image-sensor.patch new file mode 100644 index 00000000000..139cd582840 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1494-dtoverlays-Add-overlay-for-Sony-IMX415-image-sensor.patch @@ -0,0 +1,214 @@ +From 384e58f63a3a328f7f656052b6357f3408aac6c3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 31 Dec 2024 20:33:46 +0000 +Subject: [PATCH] dtoverlays: Add overlay for Sony IMX415 image sensor + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 31 +++++ + arch/arm/boot/dts/overlays/imx415-overlay.dts | 116 ++++++++++++++++++ + arch/arm/boot/dts/overlays/imx415.dtsi | 27 ++++ + 4 files changed, 175 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/imx415-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/imx415.dtsi + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + imx296.dtbo \ + imx327.dtbo \ + imx378.dtbo \ ++ imx415.dtbo \ + imx462.dtbo \ + imx477.dtbo \ + imx500.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2859,6 +2859,37 @@ Params: rotation Mounting + 450000000 (default), 453000000, 456000000. + + ++Name: imx415 ++Info: Sony IMX415 camera module. ++ Uses Unicam 1, which is the standard camera connector on most Pi ++ variants. By default this uses 4 CSI2 data lanes, so requires a ++ Compute Module or Pi5. ++Load: dtoverlay=imx415, ++Params: addr Set I2C address of sensor. Valid values are ++ 0x10, 0x1a, 0x36 and 0x37. Default is 0x37. ++ 4lane Enable 4 CSI2 data lanes. ++ clock-frequency Sets the clock frequency to match that used on ++ the board. ++ Valid values are 24, 27, 37.125, 72, or ++ 74.25MHz. ++ The default is 24MHz. ++ Note that the link frequencies permitted vary ++ based on the oscillator used. ++ link-frequency Confgures the link frequency to be used. Note ++ that the permitted values vary based on ++ clock-frequency and number of lanes. ++ The default is 360MHz for 720Mbit/s. ++ orientation Sensor orientation (0 = front, 1 = rear, ++ 2 = external, default external) ++ rotation Mounting rotation of the camera sensor (0 or ++ 180, default 0) ++ 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). ++ vcm Enable ad5398 VCM associated with the sensor. ++ ++ + Name: imx462 + Info: Sony IMX462 camera module. + Uses Unicam 1, which is the standard camera connector on most Pi +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx415-overlay.dts +@@ -0,0 +1,116 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Definitions for IMX415 camera module on VC I2C bus ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/{ ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c0if>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ clk_frag: fragment@1 { ++ target = <&cam1_clk>; ++ cam_clk: __overlay__ { ++ status = "okay"; ++ clock-frequency = <24000000>; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c0mux>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ reg_frag: fragment@3 { ++ target = <&cam1_reg>; ++ cam_reg: __overlay__ { ++ startup-delay-us = <100000>; ++ }; ++ }; ++ ++ i2c_frag: fragment@100 { ++ target = <&i2c_csi_dsi>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ #include "imx415.dtsi" ++ ++ vcm: ad5398@c { ++ compatible = "adi,ad5398"; ++ reg = <0x0c>; ++ status = "disabled"; ++ VANA-supply = <&cam1_reg>; ++ }; ++ }; ++ }; ++ ++ 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; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@201 { ++ target = <&cam_endpoint>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ ++ fragment@202 { ++ target = <&csi_ep>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ ++ ++ __overrides__ { ++ addr = <&cam_node>, "reg:0"; ++ 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>, ++ <®_frag>, "target:0=",<&cam0_reg>, ++ <&clk_frag>, "target:0=",<&cam0_clk>, ++ <&cam_node>, "clocks:0=",<&cam0_clk>, ++ <&cam_node>, "avdd-supply:0=",<&cam0_reg>, ++ <&vcm>, "VANA-supply:0=", <&cam0_reg>; ++ vcm = <&vcm>, "status=okay", ++ <&cam_node>,"lens-focus:0=", <&vcm>; ++ clock-frequency = <&cam_clk>, "clock-frequency:0"; ++ link-frequency = <&cam_endpoint>,"link-frequencies#0"; ++ 4lane = <0>, "+201+202"; ++ }; ++}; ++ ++&cam_node { ++ status = "okay"; ++}; ++ ++&cam_endpoint { ++ remote-endpoint = <&csi_ep>; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/imx415.dtsi +@@ -0,0 +1,27 @@ ++// Fragment that configures an imx415 ++ ++cam_node: imx415@37 { ++ compatible = "sony,imx415"; ++ reg = <0x37>; ++ status = "disabled"; ++ ++ clocks = <&cam1_clk>; ++ clock-names = "inck"; ++ ++ avdd-supply = <&cam1_reg>; /* 2.8v */ ++ dvdd-supply = <&cam_dummy_reg>; /* 1.8v */ ++ ovdd-supply = <&cam_dummy_reg>; /* 1.2v */ ++ ++ rotation = <180>; ++ orientation = <2>; ++ ++ port { ++ cam_endpoint: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ //clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <360000000>; ++ }; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1495-media-i2c-imx415-Add-read-write-control-of-VBLANK.patch b/target/linux/bcm27xx/patches-6.6/950-1495-media-i2c-imx415-Add-read-write-control-of-VBLANK.patch new file mode 100644 index 00000000000..aee483b9794 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1495-media-i2c-imx415-Add-read-write-control-of-VBLANK.patch @@ -0,0 +1,146 @@ +From 4e8d73ce89c6dd6fdcb8dd7df8310762707c5b1a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 1 Jan 2025 14:18:25 +0000 +Subject: [PATCH] media: i2c: imx415: Add read/write control of VBLANK + +This also requires that the ranges for the exposure control +are updated. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/imx415.c | 52 +++++++++++++++++++++++++------------- + 1 file changed, 34 insertions(+), 18 deletions(-) + +--- a/drivers/media/i2c/imx415.c ++++ b/drivers/media/i2c/imx415.c +@@ -25,6 +25,7 @@ + #define IMX415_PIXEL_ARRAY_WIDTH 3864 + #define IMX415_PIXEL_ARRAY_HEIGHT 2192 + #define IMX415_PIXEL_ARRAY_VBLANK 58 ++#define IMX415_EXPOSURE_OFFSET 8 + + #define IMX415_NUM_CLK_PARAM_REGS 11 + +@@ -56,6 +57,7 @@ + #define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0) + #define IMX415_DRV IMX415_REG_8BIT(0x30C1) + #define IMX415_VMAX IMX415_REG_24BIT(0x3024) ++#define IMX415_VMAX_MAX 0xfffff + #define IMX415_HMAX IMX415_REG_16BIT(0x3028) + #define IMX415_SHR0 IMX415_REG_24BIT(0x3050) + #define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) +@@ -457,7 +459,6 @@ static const struct imx415_clk_params im + + /* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ + static const struct imx415_reg imx415_mode_2_720[] = { +- { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x07F0 }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x006F }, +@@ -473,7 +474,6 @@ static const struct imx415_reg imx415_mo + + /* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ + static const struct imx415_reg imx415_mode_2_1440[] = { +- { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x042A }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x009F }, +@@ -489,7 +489,6 @@ static const struct imx415_reg imx415_mo + + /* all-pixel 4-lane 891 Mbps 30 Hz mode */ + static const struct imx415_reg imx415_mode_4_891[] = { +- { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x044C }, + { IMX415_LANEMODE, IMX415_LANEMODE_4 }, + { IMX415_TCLKPOST, 0x007F }, +@@ -617,6 +616,7 @@ struct imx415 { + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *exposure; + + unsigned int cur_mode; + unsigned int num_data_lanes; +@@ -795,16 +795,37 @@ static int imx415_s_ctrl(struct v4l2_ctr + ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; ++ u32 exposure_max; + unsigned int vmax; + unsigned int flip; +- +- if (!sensor->streaming) +- return 0; ++ int ret; + + state = v4l2_subdev_get_locked_active_state(&sensor->subdev); + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + ++ if (ctrl->id == V4L2_CID_VBLANK) { ++ exposure_max = format->height + ctrl->val - ++ IMX415_EXPOSURE_OFFSET; ++ __v4l2_ctrl_modify_range(sensor->exposure, ++ sensor->exposure->minimum, ++ exposure_max, sensor->exposure->step, ++ sensor->exposure->default_value); ++ } ++ ++ if (!sensor->streaming) ++ return 0; ++ + switch (ctrl->id) { ++ case V4L2_CID_VBLANK: ++ ret = imx415_write(sensor, IMX415_VMAX, ++ format->height + ctrl->val); ++ if (ret) ++ return ret; ++ /* ++ * Deliberately fall through as exposure is set based on VMAX ++ * which has just changed. ++ */ ++ fallthrough; + case V4L2_CID_EXPOSURE: + /* clamp the exposure value to VMAX. */ + vmax = format->height + sensor->vblank->cur.val; +@@ -840,7 +861,8 @@ static int imx415_ctrls_init(struct imx4 + u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate; + u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate; + u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT + +- IMX415_PIXEL_ARRAY_VBLANK - 8; ++ IMX415_PIXEL_ARRAY_VBLANK - ++ IMX415_EXPOSURE_OFFSET; + u32 hblank; + unsigned int i; + int ret; +@@ -869,8 +891,9 @@ static int imx415_ctrls_init(struct imx4 + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + +- v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE, +- 4, exposure_max, 1, exposure_max); ++ sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, ++ exposure_max, 1, exposure_max); + + v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN, +@@ -887,16 +910,9 @@ static int imx415_ctrls_init(struct imx4 + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VBLANK, + IMX415_PIXEL_ARRAY_VBLANK, +- IMX415_PIXEL_ARRAY_VBLANK, 1, +- IMX415_PIXEL_ARRAY_VBLANK); +- if (sensor->vblank) +- sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; +- +- /* +- * The pixel rate used here is a virtual value and can be used for +- * calculating the frame rate together with hblank. It may not +- * necessarily be the physically correct pixel clock. +- */ ++ IMX415_VMAX_MAX - IMX415_PIXEL_ARRAY_HEIGHT, ++ 1, IMX415_PIXEL_ARRAY_VBLANK); ++ + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1496-media-i2c-imx415-Make-HBLANK-controllable-and-in-con.patch b/target/linux/bcm27xx/patches-6.6/950-1496-media-i2c-imx415-Make-HBLANK-controllable-and-in-con.patch new file mode 100644 index 00000000000..7ad9e11953b --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1496-media-i2c-imx415-Make-HBLANK-controllable-and-in-con.patch @@ -0,0 +1,231 @@ +From 6722e1358768671c1e5761aa092efb4ae62b2c46 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 1 Jan 2025 17:01:34 +0000 +Subject: [PATCH] media: i2c: imx415: Make HBLANK controllable and in + consistent units + +The control of HMAX documented in the datasheet is consistent +with being in terms of a scaled INCK, being always 72MHz or +74.25MHz. It is NOT link frequency dependent, but the minimum +value for HMAX is dictated by the link frequency. + +If PIXEL_RATE is defined as being 12 times the 72 or 74.25MHz, +and all values are scaled down again when writing HMAX, then +the numbers all work out regardless of INCK or link frequency. +Retain an hmax_min (set to the same value as the previous fixed +hmax register value) to set as the default value to avoid changing +the behaviour for existing users. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/imx415.c | 86 +++++++++++++++++--------------------- + 1 file changed, 38 insertions(+), 48 deletions(-) + +--- a/drivers/media/i2c/imx415.c ++++ b/drivers/media/i2c/imx415.c +@@ -27,6 +27,9 @@ + #define IMX415_PIXEL_ARRAY_VBLANK 58 + #define IMX415_EXPOSURE_OFFSET 8 + ++#define IMX415_PIXEL_RATE_74_25MHZ 891000000 ++#define IMX415_PIXEL_RATE_72MHZ 864000000 ++ + #define IMX415_NUM_CLK_PARAM_REGS 11 + + #define IMX415_REG_8BIT(n) ((1 << 16) | (n)) +@@ -59,6 +62,8 @@ + #define IMX415_VMAX IMX415_REG_24BIT(0x3024) + #define IMX415_VMAX_MAX 0xfffff + #define IMX415_HMAX IMX415_REG_16BIT(0x3028) ++#define IMX415_HMAX_MAX 0xffff ++#define IMX415_HMAX_MULTIPLIER 12 + #define IMX415_SHR0 IMX415_REG_24BIT(0x3050) + #define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) + #define IMX415_AGAIN_MIN 0 +@@ -459,7 +464,6 @@ static const struct imx415_clk_params im + + /* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ + static const struct imx415_reg imx415_mode_2_720[] = { +- { IMX415_HMAX, 0x07F0 }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x006F }, + { IMX415_TCLKPREPARE, 0x002F }, +@@ -474,7 +478,6 @@ static const struct imx415_reg imx415_mo + + /* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ + static const struct imx415_reg imx415_mode_2_1440[] = { +- { IMX415_HMAX, 0x042A }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x009F }, + { IMX415_TCLKPREPARE, 0x0057 }, +@@ -489,7 +492,6 @@ static const struct imx415_reg imx415_mo + + /* all-pixel 4-lane 891 Mbps 30 Hz mode */ + static const struct imx415_reg imx415_mode_4_891[] = { +- { IMX415_HMAX, 0x044C }, + { IMX415_LANEMODE, IMX415_LANEMODE_4 }, + { IMX415_TCLKPOST, 0x007F }, + { IMX415_TCLKPREPARE, 0x0037 }, +@@ -507,39 +509,10 @@ struct imx415_mode_reg_list { + const struct imx415_reg *regs; + }; + +-/* +- * Mode : number of lanes, lane rate and frame rate dependent settings +- * +- * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl +- * interface. These values can not be found in the data sheet and should be +- * treated as virtual values. Use following table when adding new modes. +- * +- * lane_rate lanes fps hmax_pix pixel_rate +- * +- * 594 2 10.000 4400 99000000 +- * 891 2 15.000 4400 148500000 +- * 720 2 15.748 4064 144000000 +- * 1782 2 30.000 4400 297000000 +- * 2079 2 30.000 4400 297000000 +- * 1440 2 30.019 4510 304615385 +- * +- * 594 4 20.000 5500 247500000 +- * 594 4 25.000 4400 247500000 +- * 720 4 25.000 4400 247500000 +- * 720 4 30.019 4510 304615385 +- * 891 4 30.000 4400 297000000 +- * 1440 4 30.019 4510 304615385 +- * 1440 4 60.038 4510 609230769 +- * 1485 4 60.000 4400 594000000 +- * 1782 4 60.000 4400 594000000 +- * 2079 4 60.000 4400 594000000 +- * 2376 4 90.164 4392 891000000 +- */ + struct imx415_mode { + u64 lane_rate; + u32 lanes; +- u32 hmax_pix; +- u64 pixel_rate; ++ u32 hmax_min; + struct imx415_mode_reg_list reg_list; + }; + +@@ -548,8 +521,7 @@ static const struct imx415_mode supporte + { + .lane_rate = 720000000, + .lanes = 2, +- .hmax_pix = 4064, +- .pixel_rate = 144000000, ++ .hmax_min = 2032, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_720), + .regs = imx415_mode_2_720, +@@ -558,8 +530,7 @@ static const struct imx415_mode supporte + { + .lane_rate = 1440000000, + .lanes = 2, +- .hmax_pix = 4510, +- .pixel_rate = 304615385, ++ .hmax_min = 1066, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440), + .regs = imx415_mode_2_1440, +@@ -568,8 +539,7 @@ static const struct imx415_mode supporte + { + .lane_rate = 891000000, + .lanes = 4, +- .hmax_pix = 4400, +- .pixel_rate = 297000000, ++ .hmax_min = 1100, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_4_891), + .regs = imx415_mode_4_891, +@@ -601,6 +571,7 @@ static const char *const imx415_test_pat + struct imx415 { + struct device *dev; + struct clk *clk; ++ unsigned long pixel_rate; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)]; + struct gpio_desc *reset; + struct regmap *regmap; +@@ -614,6 +585,7 @@ struct imx415 { + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *vblank; ++ struct v4l2_ctrl *hblank; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *exposure; +@@ -845,6 +817,11 @@ static int imx415_s_ctrl(struct v4l2_ctr + case V4L2_CID_TEST_PATTERN: + return imx415_set_testpattern(sensor, ctrl->val); + ++ case V4L2_CID_HBLANK: ++ return imx415_write(sensor, IMX415_HMAX, ++ (format->width + ctrl->val) / ++ IMX415_HMAX_MULTIPLIER); ++ + default: + return -EINVAL; + } +@@ -858,12 +835,11 @@ static int imx415_ctrls_init(struct imx4 + { + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *ctrl; +- u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate; + u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate; + u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT + + IMX415_PIXEL_ARRAY_VBLANK - + IMX415_EXPOSURE_OFFSET; +- u32 hblank; ++ u32 hblank_min, hblank_max; + unsigned int i; + int ret; + +@@ -900,12 +876,14 @@ static int imx415_ctrls_init(struct imx4 + IMX415_AGAIN_MAX, IMX415_AGAIN_STEP, + IMX415_AGAIN_MIN); + +- hblank = supported_modes[sensor->cur_mode].hmax_pix - +- IMX415_PIXEL_ARRAY_WIDTH; ++ hblank_min = (supported_modes[sensor->cur_mode].hmax_min * ++ IMX415_HMAX_MULTIPLIER) - IMX415_PIXEL_ARRAY_WIDTH; ++ hblank_max = (IMX415_HMAX_MAX * IMX415_HMAX_MULTIPLIER) - ++ IMX415_PIXEL_ARRAY_WIDTH; + ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, +- V4L2_CID_HBLANK, hblank, hblank, 1, hblank); +- if (ctrl) +- ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ V4L2_CID_HBLANK, hblank_min, ++ hblank_max, IMX415_HMAX_MULTIPLIER, ++ hblank_min); + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VBLANK, +@@ -913,8 +891,9 @@ static int imx415_ctrls_init(struct imx4 + IMX415_VMAX_MAX - IMX415_PIXEL_ARRAY_HEIGHT, + 1, IMX415_PIXEL_ARRAY_VBLANK); + +- v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, +- pixel_rate, 1, pixel_rate); ++ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, ++ sensor->pixel_rate, sensor->pixel_rate, 1, ++ sensor->pixel_rate); + + sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); +@@ -1410,6 +1389,17 @@ static int imx415_parse_hw_config(struct + "no valid sensor mode defined\n"); + goto done_endpoint_free; + } ++ switch (inck) { ++ case 27000000: ++ case 37125000: ++ case 74250000: ++ sensor->pixel_rate = IMX415_PIXEL_RATE_74_25MHZ; ++ break; ++ case 24000000: ++ case 72000000: ++ sensor->pixel_rate = IMX415_PIXEL_RATE_72MHZ; ++ break; ++ } + + lane_rate = supported_modes[sensor->cur_mode].lane_rate; + for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { diff --git a/target/linux/bcm27xx/patches-6.6/950-1497-media-i2c-imx415-Link-frequencies-are-not-exclusive-.patch b/target/linux/bcm27xx/patches-6.6/950-1497-media-i2c-imx415-Link-frequencies-are-not-exclusive-.patch new file mode 100644 index 00000000000..d0375058c3f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1497-media-i2c-imx415-Link-frequencies-are-not-exclusive-.patch @@ -0,0 +1,136 @@ +From 0292614f8cd061f71f975dae7d74fe5324545321 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 2 Jan 2025 12:43:01 +0000 +Subject: [PATCH] media: i2c: imx415: Link frequencies are not exclusive to num + lanes + +The link frequencies are equally valid in 2 or 4 lane modes, but +they change the hmax_min value for the mode as the MIPI block +has to have sufficient time to send the pixel data for each line. + +Remove the association with number of lanes, and add hmax_min +configuration for both lane options. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/imx415.c | 49 +++++++++++++++++--------------------- + 1 file changed, 22 insertions(+), 27 deletions(-) + +--- a/drivers/media/i2c/imx415.c ++++ b/drivers/media/i2c/imx415.c +@@ -462,9 +462,8 @@ static const struct imx415_clk_params im + }, + }; + +-/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ +-static const struct imx415_reg imx415_mode_2_720[] = { +- { IMX415_LANEMODE, IMX415_LANEMODE_2 }, ++/* 720 Mbps CSI configuration */ ++static const struct imx415_reg imx415_linkrate_720mbps[] = { + { IMX415_TCLKPOST, 0x006F }, + { IMX415_TCLKPREPARE, 0x002F }, + { IMX415_TCLKTRAIL, 0x002F }, +@@ -476,9 +475,8 @@ static const struct imx415_reg imx415_mo + { IMX415_TLPX, 0x0027 }, + }; + +-/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ +-static const struct imx415_reg imx415_mode_2_1440[] = { +- { IMX415_LANEMODE, IMX415_LANEMODE_2 }, ++/* 1440 Mbps CSI configuration */ ++static const struct imx415_reg imx415_linkrate_1440mbps[] = { + { IMX415_TCLKPOST, 0x009F }, + { IMX415_TCLKPREPARE, 0x0057 }, + { IMX415_TCLKTRAIL, 0x0057 }, +@@ -490,9 +488,8 @@ static const struct imx415_reg imx415_mo + { IMX415_TLPX, 0x004F }, + }; + +-/* all-pixel 4-lane 891 Mbps 30 Hz mode */ +-static const struct imx415_reg imx415_mode_4_891[] = { +- { IMX415_LANEMODE, IMX415_LANEMODE_4 }, ++/* 891 Mbps */ ++static const struct imx415_reg imx415_linkrate_891mbps[] = { + { IMX415_TCLKPOST, 0x007F }, + { IMX415_TCLKPREPARE, 0x0037 }, + { IMX415_TCLKTRAIL, 0x0037 }, +@@ -511,8 +508,7 @@ struct imx415_mode_reg_list { + + struct imx415_mode { + u64 lane_rate; +- u32 lanes; +- u32 hmax_min; ++ u32 hmax_min[2]; + struct imx415_mode_reg_list reg_list; + }; + +@@ -520,29 +516,26 @@ struct imx415_mode { + static const struct imx415_mode supported_modes[] = { + { + .lane_rate = 720000000, +- .lanes = 2, +- .hmax_min = 2032, ++ .hmax_min = { 2032, 1066 }, + .reg_list = { +- .num_of_regs = ARRAY_SIZE(imx415_mode_2_720), +- .regs = imx415_mode_2_720, ++ .num_of_regs = ARRAY_SIZE(imx415_linkrate_720mbps), ++ .regs = imx415_linkrate_720mbps, + }, + }, + { + .lane_rate = 1440000000, +- .lanes = 2, +- .hmax_min = 1066, ++ .hmax_min = { 1066, 533 }, + .reg_list = { +- .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440), +- .regs = imx415_mode_2_1440, ++ .num_of_regs = ARRAY_SIZE(imx415_linkrate_1440mbps), ++ .regs = imx415_linkrate_1440mbps, + }, + }, + { + .lane_rate = 891000000, +- .lanes = 4, +- .hmax_min = 1100, ++ .hmax_min = { 1100, 550 }, + .reg_list = { +- .num_of_regs = ARRAY_SIZE(imx415_mode_4_891), +- .regs = imx415_mode_4_891, ++ .num_of_regs = ARRAY_SIZE(imx415_linkrate_891mbps), ++ .regs = imx415_linkrate_891mbps, + }, + }, + }; +@@ -876,7 +869,7 @@ static int imx415_ctrls_init(struct imx4 + IMX415_AGAIN_MAX, IMX415_AGAIN_STEP, + IMX415_AGAIN_MIN); + +- hblank_min = (supported_modes[sensor->cur_mode].hmax_min * ++ hblank_min = (supported_modes[sensor->cur_mode].hmax_min[sensor->num_data_lanes == 2 ? 0 : 1] * + IMX415_HMAX_MULTIPLIER) - IMX415_PIXEL_ARRAY_WIDTH; + hblank_max = (IMX415_HMAX_MAX * IMX415_HMAX_MULTIPLIER) - + IMX415_PIXEL_ARRAY_WIDTH; +@@ -944,7 +937,11 @@ static int imx415_set_mode(struct imx415 + return ret; + } + +- return 0; ++ ret = imx415_write(sensor, IMX415_LANEMODE, ++ sensor->num_data_lanes == 2 ? IMX415_LANEMODE_2 : ++ IMX415_LANEMODE_4); ++ ++ return ret; + } + + static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) +@@ -1373,8 +1370,6 @@ static int imx415_parse_hw_config(struct + } + + for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) { +- if (sensor->num_data_lanes != supported_modes[j].lanes) +- continue; + if (bus_cfg.link_frequencies[i] * 2 != + supported_modes[j].lane_rate) + continue; diff --git a/target/linux/bcm27xx/patches-6.6/950-1498-dts-bcm2711-PL011-UARTs-are-actually-r1p5.patch b/target/linux/bcm27xx/patches-6.6/950-1498-dts-bcm2711-PL011-UARTs-are-actually-r1p5.patch new file mode 100644 index 00000000000..a184b3134a4 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1498-dts-bcm2711-PL011-UARTs-are-actually-r1p5.patch @@ -0,0 +1,60 @@ +From 87fc066350358ce45f5ad52424c8a2e351b1720c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 7 Jan 2025 12:05:41 +0000 +Subject: [PATCH] dts: bcm2711: PL011 UARTs are actually r1p5 + +The ARM PL011 UART instances in BCM2711 are r1p5 spec, which means they +have 32-entry FIFOs. The correct periphid value for this is 0x00341011. +Thanks to N Buchwitz for pointing this out. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/broadcom/bcm2711.dtsi | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi +@@ -134,7 +134,7 @@ + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -145,7 +145,7 @@ + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -156,7 +156,7 @@ + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -167,7 +167,7 @@ + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -1155,6 +1155,7 @@ + }; + + &uart0 { ++ arm,primecell-periphid = <0x00341011>; + interrupts = ; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1499-dts-bcm2712-PL011-UARTs-are-actually-r1p5.patch b/target/linux/bcm27xx/patches-6.6/950-1499-dts-bcm2712-PL011-UARTs-are-actually-r1p5.patch new file mode 100644 index 00000000000..520d1d64252 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1499-dts-bcm2712-PL011-UARTs-are-actually-r1p5.patch @@ -0,0 +1,43 @@ +From 602be52637ecca0b247cf832c8a4ec345844d325 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 7 Jan 2025 12:09:48 +0000 +Subject: [PATCH] dts: bcm2712: PL011 UARTs are actually r1p5 + +The ARM PL011 UART instances in BCM2712 are r1p5 spec, which means they +have 32-entry FIFOs. The correct periphid value for this is 0x00341011. +Thanks to N Buchwitz for pointing this out. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -190,7 +190,7 @@ + clocks = <&clk_uart>, + <&clk_vpu>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -201,7 +201,7 @@ + clocks = <&clk_uart>, + <&clk_vpu>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + +@@ -212,7 +212,7 @@ + clocks = <&clk_uart>, + <&clk_vpu>; + clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; ++ arm,primecell-periphid = <0x00341011>; + status = "disabled"; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1500-dts-rp1-PL011-UARTs-are-actually-r1p5.patch b/target/linux/bcm27xx/patches-6.6/950-1500-dts-rp1-PL011-UARTs-are-actually-r1p5.patch new file mode 100644 index 00000000000..9363036ccb9 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1500-dts-rp1-PL011-UARTs-are-actually-r1p5.patch @@ -0,0 +1,70 @@ +From 7a4972f36a63eba4d862115265a7bf77ac1e4129 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 7 Jan 2025 12:11:10 +0000 +Subject: [PATCH] dts: rp1: PL011 UARTs are actually r1p5 + +The ARM PL011 UART instances in RP1 are r1p5 spec, which means they +have 32-entry FIFOs. The correct periphid value for this is 0x00341011. +Thanks to N Buchwitz for pointing this out. + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/rp1.dtsi | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi ++++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi +@@ -69,7 +69,7 @@ + <&rp1_dma RP1_DMA_UART0_RX>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; +@@ -86,7 +86,7 @@ + // <&rp1_dma RP1_DMA_UART1_RX>; + // dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; +@@ -103,7 +103,7 @@ + // <&rp1_dma RP1_DMA_UART2_RX>; + // dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; +@@ -120,7 +120,7 @@ + // <&rp1_dma RP1_DMA_UART3_RX>; + // dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; +@@ -137,7 +137,7 @@ + // <&rp1_dma RP1_DMA_UART4_RX>; + // dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; +@@ -154,7 +154,7 @@ + // <&rp1_dma RP1_DMA_UART5_RX>; + // dma-names = "tx", "rx"; + pinctrl-names = "default"; +- arm,primecell-periphid = <0x00541011>; ++ arm,primecell-periphid = <0x00341011>; + uart-has-rtscts; + cts-event-workaround; + skip-init; diff --git a/target/linux/bcm27xx/patches-6.6/950-1501-ASoC-pcm512x-Demote-No-SCLK-to-debug-level.patch b/target/linux/bcm27xx/patches-6.6/950-1501-ASoC-pcm512x-Demote-No-SCLK-to-debug-level.patch new file mode 100644 index 00000000000..02857ce6db3 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1501-ASoC-pcm512x-Demote-No-SCLK-to-debug-level.patch @@ -0,0 +1,25 @@ +From 4f7341263ebd6ab2ae805c8f27191d24abc05a62 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Jan 2025 15:48:35 +0000 +Subject: [PATCH] ASoC: pcm512x: Demote "No SCLK" to debug level + +Designing a PCM512X-based soundcard with no external SCLK is a valid +choice supported by the driver. Don't alarm users with messages that +say "No SCLK, using BCLK: -2" - reclassify them as debug information. + +Signed-off-by: Phil Elwell +--- + sound/soc/codecs/pcm512x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -630,7 +630,7 @@ static int pcm512x_dai_startup_slave(str + struct regmap *regmap = pcm512x->regmap; + + if (IS_ERR(pcm512x->sclk)) { +- dev_info(dev, "No SCLK, using BCLK: %ld\n", ++ dev_dbg(dev, "No SCLK, using BCLK: %ld\n", + PTR_ERR(pcm512x->sclk)); + + /* Disable reporting of missing SCLK as an error */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1502-ASoC-allo-piano-dac-plus-Fix-volume-limiting.patch b/target/linux/bcm27xx/patches-6.6/950-1502-ASoC-allo-piano-dac-plus-Fix-volume-limiting.patch new file mode 100644 index 00000000000..f08083463fb --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1502-ASoC-allo-piano-dac-plus-Fix-volume-limiting.patch @@ -0,0 +1,58 @@ +From 4111f4ede92b1f5bf869f87c66fc39151999c42f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Jan 2025 15:46:30 +0000 +Subject: [PATCH] ASoC: allo-piano-dac-plus: Fix volume limiting + +Controls which only exist when snd_soc_register_card returns can't be +modified before then. Move the setting of volume limits to just before +the end of the probe function. + +Link: https://github.com/raspberrypi/linux/issues/6527 + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/allo-piano-dac-plus.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/sound/soc/bcm/allo-piano-dac-plus.c ++++ b/sound/soc/bcm/allo-piano-dac-plus.c +@@ -734,18 +734,6 @@ static int snd_allo_piano_dac_init(struc + if (digital_gain_0db_limit) { + int ret; + +- ret = snd_soc_limit_volume(card, "Master Playback Volume", +- 207); +- if (ret < 0) +- dev_warn(card->dev, "Failed to set master volume limit: %d\n", +- ret); +- +- ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume", +- 207); +- if (ret < 0) +- dev_warn(card->dev, "Failed to set subwoofer volume limit: %d\n", +- ret); +- + //Set volume limit on both dacs + for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) { + char cname[256]; +@@ -1000,6 +988,20 @@ static int snd_allo_piano_dac_probe(stru + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); + ++ if (digital_gain_0db_limit) { ++ ret = snd_soc_limit_volume(card, "Master Playback Volume", ++ 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set master volume limit: %d\n", ++ ret); ++ ++ ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume", ++ 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set subwoofer volume limit: %d\n", ++ ret); ++ } ++ + if ((mute_gpio[0]) && (mute_gpio[1])) + snd_allo_piano_gpio_mute(&snd_allo_piano_dac); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1503-ASoC-allo-piano-dac-plus-Remove-pointless-code.patch b/target/linux/bcm27xx/patches-6.6/950-1503-ASoC-allo-piano-dac-plus-Remove-pointless-code.patch new file mode 100644 index 00000000000..bb5c21d4291 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1503-ASoC-allo-piano-dac-plus-Remove-pointless-code.patch @@ -0,0 +1,53 @@ +From 62c33972e3eb724d80179fb71b05e923920f0b0d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Jan 2025 16:05:02 +0000 +Subject: [PATCH] ASoC: allo-piano-dac-plus: Remove pointless code + +The codec control Digital Playback Volume is one of the controls deleted +by the allo-piano-dac-plus driver. It is effectively replaced by the +soundcard controls Master Playback Volume and Subwoofer Playback Volume. + +Delete the code that sets the volume limit on those codec controls - the +limits on the soundcard volume controls are sufficient. + +Signed-off-by: Phil Elwell +--- + sound/soc/bcm/allo-piano-dac-plus.c | 20 +------------------- + 1 file changed, 1 insertion(+), 19 deletions(-) + +--- a/sound/soc/bcm/allo-piano-dac-plus.c ++++ b/sound/soc/bcm/allo-piano-dac-plus.c +@@ -731,21 +731,6 @@ static int snd_allo_piano_dac_init(struc + + mutex_init(&glb_ptr->lock); + +- if (digital_gain_0db_limit) { +- int ret; +- +- //Set volume limit on both dacs +- for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) { +- char cname[256]; +- +- sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[0]); +- ret = snd_soc_limit_volume(card, cname, 207); +- if (ret < 0) +- dev_warn(card->dev, "Failed to set %s volume limit: %d\n", +- cname, ret); +- } +- } +- + // Remove codec controls + for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) { + for (j = 0; j < ARRAY_SIZE(codec_ctl_name); j++) { +@@ -753,10 +738,7 @@ static int snd_allo_piano_dac_init(struc + + sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[j]); + kctl = snd_soc_card_get_kcontrol(card, cname); +- if (!kctl) { +- dev_err(rtd->card->dev, "Control %s not found\n", +- cname); +- } else { ++ if (kctl) { + kctl->vd[0].access = + SNDRV_CTL_ELEM_ACCESS_READWRITE; + snd_ctl_remove(card->snd_card, kctl); diff --git a/target/linux/bcm27xx/patches-6.6/950-1505-DT-bcm2712-override-supports-cqe-to-a-cell.patch b/target/linux/bcm27xx/patches-6.6/950-1505-DT-bcm2712-override-supports-cqe-to-a-cell.patch new file mode 100644 index 00000000000..c95c1d432ea --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1505-DT-bcm2712-override-supports-cqe-to-a-cell.patch @@ -0,0 +1,90 @@ +From 301420a8cc44ee457670e015adc3a08cfc4531a9 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Jan 2025 14:58:37 +0000 +Subject: [PATCH] DT: bcm2712: override supports-cqe to a cell + +We want to be able to control the interop surface exposed by Command +Queueing across bcm2712 products to a more restrictive default, with +selectable disable and permissive behaviour. + +Changing the bool to a cell lets it relay a tristate value. + +Also add the override parameter to CM5 as CM5-lite may interface with +arbitrary eMMC or SD cards. + +Signed-off-by: Jonathan Bell +--- + arch/arm/boot/dts/overlays/README | 11 ++++++++--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 4 ++-- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 3 ++- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 +- + 4 files changed, 13 insertions(+), 7 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -405,9 +405,14 @@ Params: + non-lite SKU of CM4). + (default "on") + +- sd_cqe Set to "off" to disable Command Queueing if you +- have an incompatible Class A2 SD card +- (Pi 5 only, default "on") ++ sd_cqe Modify Command Queuing behaviour on the main SD ++ interface. Legal values are: ++ 0: disable CQ ++ 1: allow CQ for known-good SD A2 cards, and all ++ eMMC cards ++ 2: allow CQ for all SD A2 cards that aren't ++ known-bad, and all eMMC cards. ++ (2712 only, default "1") + + 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,7 +365,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + sd-uhs-sdr50; + sd-uhs-ddr50; + sd-uhs-sdr104; +- supports-cqe; ++ supports-cqe = <1>; + cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>; + //no-1-8-v; + status = "okay"; +@@ -745,6 +745,6 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + + / { + __overrides__ { +- sd_cqe = <&sdio1>, "supports-cqe?"; ++ sd_cqe = <&sdio1>, "supports-cqe:0"; + }; + }; +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -339,7 +339,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + broken-cd; +- supports-cqe; ++ supports-cqe = <1>; + status = "okay"; + }; + +@@ -752,5 +752,6 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + <&ant2>, "output-low?=on"; + noanthogs = <&ant1>,"status=disabled", + <&ant2>, "status=disabled"; ++ sd_cqe = <&sdio1>, "supports-cqe:0"; + }; + }; +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -1210,7 +1210,7 @@ + clocks = <&clk_emmc2>; + sdhci-caps-mask = <0x0000C000 0x0>; + sdhci-caps = <0x0 0x0>; +- supports-cqe; ++ supports-cqe = <1>; + mmc-ddr-3_3v; + status = "disabled"; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1506-mmc-sd-filter-card-CQ-support-based-on-an-allow-list.patch b/target/linux/bcm27xx/patches-6.6/950-1506-mmc-sd-filter-card-CQ-support-based-on-an-allow-list.patch new file mode 100644 index 00000000000..e5148707bda --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1506-mmc-sd-filter-card-CQ-support-based-on-an-allow-list.patch @@ -0,0 +1,57 @@ +From d70a60eb03ae4fc687b91b5f6c4684000be21c5f Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Jan 2025 15:09:53 +0000 +Subject: [PATCH] mmc: sd: filter card CQ support based on an allow-list + +We have found that many SD cards in the field, even of the same make and +model, have latent bugs in their CQ implementation. Some product lines +have fewer bugs with newer manufacture dates, but this is not a +guarantee that a particular card is at a particular firmware revision +level. + +Many of these bugs lead to card hangs or data corruption. Add a quirk to +mark a card as having a tested, working CQ implementation and ignore the +capability if absent. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/card.h | 5 +++++ + drivers/mmc/core/sd.c | 4 ++++ + include/linux/mmc/card.h | 1 + + 3 files changed, 10 insertions(+) + +--- a/drivers/mmc/core/card.h ++++ b/drivers/mmc/core/card.h +@@ -292,4 +292,9 @@ static inline int mmc_card_broken_sd_pow + return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY; + } + ++static inline int mmc_card_working_sd_cq(const struct mmc_card *c) ++{ ++ return c->quirks & MMC_QUIRK_WORKING_SD_CQ; ++} ++ + #endif +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -1506,6 +1506,10 @@ cont: + goto free_card; + } + ++ /* Disallow command queueing on unvetted cards */ ++ if (!mmc_card_working_sd_cq(card)) ++ card->ext_csd.cmdq_support = false; ++ + /* Enable command queueing if supported */ + if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) { + /* +--- a/include/linux/mmc/card.h ++++ b/include/linux/mmc/card.h +@@ -297,6 +297,7 @@ struct mmc_card { + #define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */ + #define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */ + #define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */ ++#define MMC_QUIRK_WORKING_SD_CQ (1<<30) /* SD card has known-good CQ implementation */ + #define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */ + + bool written_flag; /* Indicates eMMC has been written since power on */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1507-mmc-set-MMC_QUIRK_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch b/target/linux/bcm27xx/patches-6.6/950-1507-mmc-set-MMC_QUIRK_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch new file mode 100644 index 00000000000..0dd1ffae716 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1507-mmc-set-MMC_QUIRK_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch @@ -0,0 +1,41 @@ +From eb4d8ffb2b007963662be7eca88baf0e5c358bd6 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Jan 2025 15:18:33 +0000 +Subject: [PATCH] mmc: set MMC_QUIRK_KNOWN_WORKING_SD_CQ on Raspberry Pi class + A2 cards + +These cards have a known-good CQ implementation and are based on a +Longsys product. Add the MANFID for Longsys SD, and the particular CID +details for the Pi card. + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/card.h | 1 + + drivers/mmc/core/quirks.h | 6 ++++++ + 2 files changed, 7 insertions(+) + +--- a/drivers/mmc/core/card.h ++++ b/drivers/mmc/core/card.h +@@ -90,6 +90,7 @@ struct mmc_fixup { + #define CID_MANFID_KINGSTON 0x70 + #define CID_MANFID_HYNIX 0x90 + #define CID_MANFID_KINGSTON_SD 0x9F ++#define CID_MANFID_LONGSYS_SD 0xAD + #define CID_MANFID_NUMONYX 0xFE + + #define END_FIXUP { NULL } +--- a/drivers/mmc/core/quirks.h ++++ b/drivers/mmc/core/quirks.h +@@ -66,6 +66,12 @@ 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), + ++ /* SD A2 allow-list - only trust CQ on these cards */ ++ /* Raspberry Pi A2 cards */ ++ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_LONGSYS_SD, 0x4c53, CID_YEAR_ANY, CID_MONTH_ANY, ++ cid_rev(1, 0, 0, 0), -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_WORKING_SD_CQ, EXT_CSD_REV_ANY), ++ + END_FIXUP + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1508-mmc-use-downstream-DT-property-to-modify-CQE-and-or-.patch b/target/linux/bcm27xx/patches-6.6/950-1508-mmc-use-downstream-DT-property-to-modify-CQE-and-or-.patch new file mode 100644 index 00000000000..2139eef8be7 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1508-mmc-use-downstream-DT-property-to-modify-CQE-and-or-.patch @@ -0,0 +1,94 @@ +From e72f42ebc9a236c023f8027a37c9351d58e28b05 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Jan 2025 16:02:27 +0000 +Subject: [PATCH] mmc: use downstream DT property to modify CQE and/or SD CQ + behaviour + +Implement a tristate-style option for "supports-cqe". If the property is +absent or zero, disable CQ completely. For 1, enable CQ unconditionally +for eMMC cards, and known-good SD cards. For 2, enable for eMMC cards, +and all SD cards that are not known-bad. + +The sdhci-brcmstb driver needs to know about the tristate as its probe +sequence would otherwise override a disable in mmc_of_parse(). + +Signed-off-by: Jonathan Bell +--- + drivers/mmc/core/host.c | 11 ++++++++++- + drivers/mmc/core/sd.c | 4 ++-- + drivers/mmc/host/sdhci-brcmstb.c | 6 ++++-- + include/linux/mmc/host.h | 1 + + 4 files changed, 17 insertions(+), 5 deletions(-) + +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -275,7 +275,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase); + int mmc_of_parse(struct mmc_host *host) + { + struct device *dev = host->parent; +- u32 bus_width, drv_type, cd_debounce_delay_ms; ++ u32 bus_width, drv_type, cd_debounce_delay_ms, cq_allow; + int ret; + + if (!dev || !dev_fwnode(dev)) +@@ -410,6 +410,15 @@ int mmc_of_parse(struct mmc_host *host) + host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V | + MMC_CAP2_HS400_ES); + ++ cq_allow = 0; ++ /* ++ * Downstream property - if a u32 and 2 instead of a bool, ++ * trust most A2 SD cards claiming CQ support. ++ */ ++ device_property_read_u32(dev, "supports-cqe", &cq_allow); ++ if (cq_allow == 2) ++ host->caps2 |= MMC_CAP2_SD_CQE_PERMISSIVE; ++ + /* Must be after "non-removable" check */ + if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) { + if (host->caps & MMC_CAP_NONREMOVABLE) +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -1506,8 +1506,8 @@ cont: + goto free_card; + } + +- /* Disallow command queueing on unvetted cards */ +- if (!mmc_card_working_sd_cq(card)) ++ /* Disallow command queueing on unvetted cards unless overridden */ ++ if (!(host->caps2 & MMC_CAP2_SD_CQE_PERMISSIVE) && !mmc_card_working_sd_cq(card)) + card->ext_csd.cmdq_support = false; + + /* Enable command queueing if supported */ +--- a/drivers/mmc/host/sdhci-brcmstb.c ++++ b/drivers/mmc/host/sdhci-brcmstb.c +@@ -511,7 +511,7 @@ static int sdhci_brcmstb_probe(struct pl + struct sdhci_pltfm_host *pltfm_host; + const struct of_device_id *match; + struct sdhci_brcmstb_priv *priv; +- u32 actual_clock_mhz; ++ u32 actual_clock_mhz, cqe; + struct sdhci_host *host; + struct resource *iomem; + bool no_pinctrl = false; +@@ -540,7 +540,9 @@ static int sdhci_brcmstb_probe(struct pl + pltfm_host->clk = clk; + + priv = sdhci_pltfm_priv(pltfm_host); +- if (device_property_read_bool(&pdev->dev, "supports-cqe")) { ++ cqe = 0; ++ device_property_read_u32(&pdev->dev, "supports-cqe", &cqe); ++ if (cqe > 0) { + priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE; + match_priv->ops->irq = sdhci_brcmstb_cqhci_irq; + } +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -427,6 +427,7 @@ struct mmc_host { + #define MMC_CAP2_CRYPTO 0 + #endif + #define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */ ++#define MMC_CAP2_SD_CQE_PERMISSIVE (1 << 31) /* Ignore allow-list for CQ capable SD card detection */ + + int fixed_drv_type; /* fixed driver type for non-removable media */ + diff --git a/target/linux/bcm27xx/patches-6.6/950-1509-misc-rp1-pio-Handle-probe-errors.patch b/target/linux/bcm27xx/patches-6.6/950-1509-misc-rp1-pio-Handle-probe-errors.patch new file mode 100644 index 00000000000..0aca41f744d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1509-misc-rp1-pio-Handle-probe-errors.patch @@ -0,0 +1,38 @@ +From e56aa0bd2b552daa4349a7eb2e6b0dec81d3e5cc Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Jan 2025 16:40:25 +0000 +Subject: [PATCH] misc: rp1-pio: Handle probe errors + +Ensure that rp1_pio_open fails if the device failed to probe. + +Link: https://github.com/raspberrypi/linux/issues/6593 + +Signed-off-by: Phil Elwell +--- + drivers/misc/rp1-pio.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/misc/rp1-pio.c ++++ b/drivers/misc/rp1-pio.c +@@ -1014,6 +1014,9 @@ struct rp1_pio_client *rp1_pio_open(void + { + struct rp1_pio_client *client; + ++ if (!g_pio) ++ return ERR_PTR(-ENOENT); ++ + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); +@@ -1265,9 +1268,8 @@ static int rp1_pio_probe(struct platform + return dev_err_probe(dev, pdev->id, "alias is missing\n"); + + fw = devm_rp1_firmware_get(dev, dev->of_node); +- if (IS_ERR(fw)) +- return PTR_ERR(fw); +- ++ if (IS_ERR_OR_NULL(fw)) ++ return dev_err_probe(dev, -ENOENT, "failed to contact RP1 firmware\n"); + ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count); + if (ret < 0) + return ret; diff --git a/target/linux/bcm27xx/patches-6.6/950-1510-firmware-rp1-Simplify-rp1_firmware_get.patch b/target/linux/bcm27xx/patches-6.6/950-1510-firmware-rp1-Simplify-rp1_firmware_get.patch new file mode 100644 index 00000000000..71a64da9591 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1510-firmware-rp1-Simplify-rp1_firmware_get.patch @@ -0,0 +1,84 @@ +From dafde0ac8b6d4b21578a677c8afad8714af47aaf Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 9 Jan 2025 16:33:37 +0000 +Subject: [PATCH] firmware: rp1: Simplify rp1_firmware_get + +Simplify the implementation of rp1_firmware_get, requiring its clients +to have a valid 'firmware' property. Also make it return NULL on error. + +Link: https://github.com/raspberrypi/linux/issues/6593 + +Signed-off-by: Phil Elwell +--- + drivers/firmware/rp1.c | 36 +++++++++++++++--------------------- + 1 file changed, 15 insertions(+), 21 deletions(-) + +--- a/drivers/firmware/rp1.c ++++ b/drivers/firmware/rp1.c +@@ -159,42 +159,36 @@ struct rp1_firmware *rp1_firmware_get(st + struct device_node *fwnode; + struct rp1_firmware *fw; + +- if (client) { +- fwnode = of_parse_phandle(client, "firmware", 0); +- if (!fwnode) +- fwnode = of_get_parent(client); +- if (fwnode && !of_device_is_compatible(fwnode, match)) { +- of_node_put(fwnode); +- fwnode = NULL; +- } +- } +- +- if (!fwnode) +- fwnode = of_find_matching_node(NULL, rp1_firmware_of_match); +- ++ if (!client) ++ return NULL; ++ fwnode = of_parse_phandle(client, "firmware", 0); + if (!fwnode) +- return ERR_PTR(-ENOENT); ++ return NULL; ++ if (!of_device_is_compatible(fwnode, match)) { ++ of_node_put(fwnode); ++ return NULL; ++ } + + pdev = of_find_device_by_node(fwnode); + of_node_put(fwnode); + + if (!pdev) +- return ERR_PTR(-EPROBE_DEFER); ++ goto err_exit; + + fw = platform_get_drvdata(pdev); + if (!fw) +- goto err_defer; ++ goto err_exit; + + if (!kref_get_unless_zero(&fw->consumers)) +- goto err_defer; ++ goto err_exit; + + put_device(&pdev->dev); + + return fw; + +-err_defer: ++err_exit: + put_device(&pdev->dev); +- return ERR_PTR(-EPROBE_DEFER); ++ return NULL; + } + EXPORT_SYMBOL_GPL(rp1_firmware_get); + +@@ -210,8 +204,8 @@ struct rp1_firmware *devm_rp1_firmware_g + int ret; + + fw = rp1_firmware_get(client); +- if (IS_ERR(fw)) +- return fw; ++ if (!fw) ++ return NULL; + + ret = devm_add_action_or_reset(dev, devm_rp1_firmware_put, fw); + if (ret) diff --git a/target/linux/bcm27xx/patches-6.6/950-1512-dts-bcm2711-Don-t-mark-timer-regs-unconfigured.patch b/target/linux/bcm27xx/patches-6.6/950-1512-dts-bcm2711-Don-t-mark-timer-regs-unconfigured.patch new file mode 100644 index 00000000000..81b37af340f --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1512-dts-bcm2711-Don-t-mark-timer-regs-unconfigured.patch @@ -0,0 +1,44 @@ +From d06cb3534b6553a1f76bef2ddaf833e23dc12a4c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 10 Jan 2025 15:45:11 +0000 +Subject: [PATCH] dts: bcm2711: Don't mark timer regs unconfigured + +The DT property arm,cpu-registers-not-fw-configured tells the kernel +that the ARM architectural timer has not been configured by the +firmware. This prevents the use of a vDSO - a faster alternative to a +syscall for some common kernel operations. + +However, on Pi 4 the firmware does configure the timer, so this property +is unnecessary. Delete it. + +Also remove it from the bcm2712.dtsi where it should never have been, +since it is only relevant to 32-bit ARM kernels. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/broadcom/bcm2711.dtsi | 2 -- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 -- + 2 files changed, 4 deletions(-) + +--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi +@@ -451,8 +451,6 @@ + IRQ_TYPE_LEVEL_LOW)>, + ; +- /* This only applies to the ARMv7 stub */ +- arm,cpu-registers-not-fw-configured; + }; + + cpus: cpus { +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -741,8 +741,6 @@ + IRQ_TYPE_LEVEL_LOW)>, + ; +- /* This only applies to the ARMv7 stub */ +- arm,cpu-registers-not-fw-configured; + }; + + cpus: cpus { diff --git a/target/linux/bcm27xx/patches-6.6/950-1513-mmc-bcm2835-sdhost-Observe-SWIOTLB-memory-limit.patch b/target/linux/bcm27xx/patches-6.6/950-1513-mmc-bcm2835-sdhost-Observe-SWIOTLB-memory-limit.patch new file mode 100644 index 00000000000..08a58f2ed5e --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1513-mmc-bcm2835-sdhost-Observe-SWIOTLB-memory-limit.patch @@ -0,0 +1,29 @@ +From dfff38316c1284c30c68d02cc424bad0562cf253 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 10 Jan 2025 16:33:13 +0000 +Subject: [PATCH] mmc: bcm2835-sdhost Observe SWIOTLB memory limit + +Make sure the sdhost driver doesn't use requests bigger than SWIOTLB +can handle. + +Copied from [1]. + +Link: https://github.com/raspberrypi/linux/issues/6589 +Signed-off-by: Phil Elwell +[1] d4dd9bccf485 ("mmc: bcm2835: Take SWIOTLB memory size limitation +into account") +--- + drivers/mmc/host/bcm2835-sdhost.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mmc/host/bcm2835-sdhost.c ++++ b/drivers/mmc/host/bcm2835-sdhost.c +@@ -1971,7 +1971,7 @@ int bcm2835_sdhost_add_host(struct platf + } + + mmc->max_segs = 128; +- mmc->max_req_size = 524288; ++ mmc->max_req_size = min_t(size_t, 524288, dma_max_mapping_size(&pdev->dev)); + mmc->max_seg_size = mmc->max_req_size; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; diff --git a/target/linux/bcm27xx/patches-6.6/950-1514-drivers-media-pisp_be-Add-support-for-YUV422-planar-.patch b/target/linux/bcm27xx/patches-6.6/950-1514-drivers-media-pisp_be-Add-support-for-YUV422-planar-.patch new file mode 100644 index 00000000000..554c9307c11 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1514-drivers-media-pisp_be-Add-support-for-YUV422-planar-.patch @@ -0,0 +1,31 @@ +From a73ecafc5532e31b184220149cc2863f625700bf Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 15 Jan 2025 09:46:25 +0000 +Subject: [PATCH] drivers: media: pisp_be: Add support for YUV422 planar format + +List V4L2_PIX_FMT_YUV422P as supported by the PiSP backend hardware. + +Signed-off-by: Naushir Patuck +--- + .../platform/raspberrypi/pisp_be/pisp_be_formats.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h ++++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h +@@ -129,6 +129,16 @@ static const struct pisp_be_format suppo + .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, + .colorspace_default = V4L2_COLORSPACE_SMPTE170M, + }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV422P, ++ /* 128 alignment to ensure U/V planes are 64 byte aligned. */ ++ .align = 128, ++ .bit_depth = 8, ++ .plane_factor = { P3(1), P3(0.5), P3(0.5) }, ++ .num_planes = 1, ++ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB, ++ .colorspace_default = V4L2_COLORSPACE_SMPTE170M, ++ }, + /* Multiplane YUV formats */ + { + .fourcc = V4L2_PIX_FMT_YUV420M, diff --git a/target/linux/bcm27xx/patches-6.6/950-1515-drivers-media-pisp_be-Remove-unused-fields-in-struct.patch b/target/linux/bcm27xx/patches-6.6/950-1515-drivers-media-pisp_be-Remove-unused-fields-in-struct.patch new file mode 100644 index 00000000000..51b8f7e7e73 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1515-drivers-media-pisp_be-Remove-unused-fields-in-struct.patch @@ -0,0 +1,82 @@ +From a452251cc286f2799969f047698c76fe3d7862b9 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Jan 2025 10:13:57 +0000 +Subject: [PATCH] drivers: media: pisp_be: Remove unused fields in struct + pisp_be_config + +These fields should not be set by either the user or the kernel driver +so remove them. Replace them with padding bytes to maintain backward +compatibility with existing userland applications. + +Signed-off-by: Naushir Patuck +--- + .../linux/media/raspberrypi/pisp_be_config.h | 42 ++----------------- + 1 file changed, 4 insertions(+), 38 deletions(-) + +--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h ++++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h +@@ -716,13 +716,6 @@ struct pisp_be_hog_buffer_config { + /** + * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration + * +- * @input_buffer: Input buffer addresses +- * @tdn_input_buffer: TDN input buffer addresses +- * @stitch_input_buffer: Stitch input buffer addresses +- * @tdn_output_buffer: TDN output buffer addresses +- * @stitch_output_buffer: Stitch output buffer addresses +- * @output_buffer: Output buffers addresses +- * @hog_buffer: HOG buffer addresses + * @global: Global PiSP configuration + * @input_format: Input image format + * @decompress: Decompress configuration +@@ -761,28 +754,10 @@ struct pisp_be_hog_buffer_config { + * @output_format: Output format configuration + * @hog: HOG configuration + * @axi: AXI bus configuration +- * @lsc_extra: LSC extra info +- * @cac_extra: CAC extra info +- * @downscale_extra: Downscaler extra info +- * @resample_extra: Resample extra info +- * @crop: Crop configuration +- * @hog_format: HOG format info +- * @dirty_flags_bayer: Bayer enable dirty flags +- * (:c:type:`pisp_be_bayer_enable`) +- * @dirty_flags_rgb: RGB enable dirty flags +- * (:c:type:`pisp_be_rgb_enable`) +- * @dirty_flags_extra: Extra dirty flags + */ + struct pisp_be_config { +- /* I/O configuration: */ +- struct pisp_be_input_buffer_config input_buffer; +- struct pisp_be_tdn_input_buffer_config tdn_input_buffer; +- struct pisp_be_stitch_input_buffer_config stitch_input_buffer; +- struct pisp_be_tdn_output_buffer_config tdn_output_buffer; +- struct pisp_be_stitch_output_buffer_config stitch_output_buffer; +- struct pisp_be_output_buffer_config +- output_buffer[PISP_BACK_END_NUM_OUTPUTS]; +- struct pisp_be_hog_buffer_config hog_buffer; ++ /* For backward compatibility */ ++ uint8_t pad0[112]; + /* Processing configuration: */ + struct pisp_be_global_config global; + struct pisp_image_format_config input_format; +@@ -823,17 +798,8 @@ struct pisp_be_config { + output_format[PISP_BACK_END_NUM_OUTPUTS]; + struct pisp_be_hog_config hog; + struct pisp_be_axi_config axi; +- /* Non-register fields: */ +- struct pisp_be_lsc_extra lsc_extra; +- struct pisp_be_cac_extra cac_extra; +- struct pisp_be_downscale_extra +- downscale_extra[PISP_BACK_END_NUM_OUTPUTS]; +- struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS]; +- struct pisp_be_crop_config crop; +- struct pisp_image_format_config hog_format; +- __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */ +- __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */ +- __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */ ++ /* For backward compatibility */ ++ uint8_t pad1[84]; + } __attribute__((packed)); + + /** diff --git a/target/linux/bcm27xx/patches-6.6/950-1516-media-imx219-Adjust-PLL-settings-based-on-the-number.patch b/target/linux/bcm27xx/patches-6.6/950-1516-media-imx219-Adjust-PLL-settings-based-on-the-number.patch new file mode 100644 index 00000000000..227ada434c8 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1516-media-imx219-Adjust-PLL-settings-based-on-the-number.patch @@ -0,0 +1,163 @@ +From 5b958efc20d381ee103103df5df0c88dc02ada18 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 16 Jan 2025 11:08:25 +0000 +Subject: [PATCH] media: imx219: Adjust PLL settings based on the number of + MIPI lanes + +Commit ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation") +added support for device tree to allow configuration of the sensor to +use 4 lanes with a link frequency of 363MHz, and amended the advertised +pixel rate to 280.8MPix/s. + +However it didn't change any of the PLL settings, so actually it would +have been running effectively overclocked in the MIPI block, and with +the frame rate and exposure calculations being wrong. + +The pixel rate and link frequency advertised were taken from the "Clock +Setting Example" section of the datasheet. However those are based on an +external clock of 12MHz, and are unachievable with a clock of 24MHz (it +seems PREPLLCLK_VT_DIV and PREPLLCK_OP_DIV can ONLY be set via the +automatic configuration doumented in "9-1-2 EXCK_FREQ setting depend on +INCK frequency). + +Dropping all support for the 363MHz link frequency would cause problems +for existing users, so allow it from device tree, but log a warning that +the requested value is not being truly applied. + +Fixes: ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation") +Co-developed-by: Peyton Howe +Signed-off-by: Peyton Howe +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/imx219.c | 83 +++++++++++++++++++++++++++++--------- + 1 file changed, 64 insertions(+), 19 deletions(-) + +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -148,10 +148,11 @@ + + /* Pixel rate is fixed for all the modes */ + #define IMX219_PIXEL_RATE 182400000 +-#define IMX219_PIXEL_RATE_4LANE 280800000 ++#define IMX219_PIXEL_RATE_4LANE 281600000 + + #define IMX219_DEFAULT_LINK_FREQ 456000000 +-#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000 ++#define IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED 363000000 ++#define IMX219_DEFAULT_LINK_FREQ_4LANE 364000000 + + /* IMX219 native and active pixel array size. */ + #define IMX219_NATIVE_WIDTH 3296U +@@ -224,15 +225,6 @@ static const struct cci_reg_sequence imx + { CCI_REG8(0x30eb), 0x05 }, + { CCI_REG8(0x30eb), 0x09 }, + +- /* PLL Clock Table */ +- { IMX219_REG_VTPXCK_DIV, 5 }, +- { IMX219_REG_VTSYCK_DIV, 1 }, +- { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */ +- { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */ +- { IMX219_REG_PLL_VT_MPY, 57 }, +- { IMX219_REG_OPSYCK_DIV, 1 }, +- { IMX219_REG_PLL_OP_MPY, 114 }, +- + /* Undocumented registers */ + { CCI_REG8(0x455e), 0x00 }, + { CCI_REG8(0x471e), 0x4b }, +@@ -316,6 +308,34 @@ static const struct cci_reg_sequence raw + { IMX219_REG_OPPXCK_DIV, 10 }, + }; + ++static const struct cci_reg_sequence imx219_2lane_regs[] = { ++ /* PLL Clock Table */ ++ { IMX219_REG_VTPXCK_DIV, 5 }, ++ { IMX219_REG_VTSYCK_DIV, 1 }, ++ { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */ ++ { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */ ++ { IMX219_REG_PLL_VT_MPY, 57 }, ++ { IMX219_REG_OPSYCK_DIV, 1 }, ++ { IMX219_REG_PLL_OP_MPY, 114 }, ++ ++ /* 2-Lane CSI Mode */ ++ { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_2_LANE_MODE }, ++}; ++ ++static const struct cci_reg_sequence imx219_4lane_regs[] = { ++ /* PLL Clock Table */ ++ { IMX219_REG_VTPXCK_DIV, 5 }, ++ { IMX219_REG_VTSYCK_DIV, 1 }, ++ { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */ ++ { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */ ++ { IMX219_REG_PLL_VT_MPY, 88 }, ++ { IMX219_REG_OPSYCK_DIV, 1 }, ++ { IMX219_REG_PLL_OP_MPY, 91 }, ++ ++ /* 4-Lane CSI Mode */ ++ { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_4_LANE_MODE }, ++}; ++ + static const s64 imx219_link_freq_menu[] = { + IMX219_DEFAULT_LINK_FREQ, + }; +@@ -941,9 +961,11 @@ static int imx219_get_selection(struct v + + static int imx219_configure_lanes(struct imx219 *imx219) + { +- return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE, +- imx219->lanes == 2 ? IMX219_CSI_2_LANE_MODE : +- IMX219_CSI_4_LANE_MODE, NULL); ++ /* Write the appropriate PLL settings for the number of MIPI lanes */ ++ return cci_multi_reg_write(imx219->regmap, ++ imx219->lanes == 2 ? imx219_2lane_regs : imx219_4lane_regs, ++ imx219->lanes == 2 ? ARRAY_SIZE(imx219_2lane_regs) : ++ ARRAY_SIZE(imx219_4lane_regs), NULL); + }; + + static int imx219_start_streaming(struct imx219 *imx219, +@@ -1334,6 +1356,7 @@ static int imx219_check_hwcfg(struct dev + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret = -EINVAL; ++ bool link_frequency_valid = false; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { +@@ -1360,11 +1383,33 @@ static int imx219_check_hwcfg(struct dev + goto error_out; + } + +- if (ep_cfg.nr_of_link_frequencies != 1 || +- (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ? +- IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) { +- dev_err(dev, "Link frequency not supported: %lld\n", +- ep_cfg.link_frequencies[0]); ++ if (ep_cfg.nr_of_link_frequencies == 1) { ++ switch (imx219->lanes) { ++ case 2: ++ if (ep_cfg.link_frequencies[0] == ++ IMX219_DEFAULT_LINK_FREQ) ++ link_frequency_valid = true; ++ break; ++ case 4: ++ if (ep_cfg.link_frequencies[0] == ++ IMX219_DEFAULT_LINK_FREQ_4LANE) ++ link_frequency_valid = true; ++ else if (ep_cfg.link_frequencies[0] == ++ IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED) { ++ dev_warn(dev, "Link frequency of %d not supported, but has been incorrectly advertised previously\n", ++ IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED); ++ dev_warn(dev, "Using link frequency of %d\n", ++ IMX219_DEFAULT_LINK_FREQ_4LANE); ++ link_frequency_valid = true; ++ } ++ break; ++ } ++ } ++ ++ if (!link_frequency_valid) { ++ dev_err_probe(dev, -EINVAL, ++ "Link frequency not supported: %lld\n", ++ ep_cfg.link_frequencies[0]); + goto error_out; + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1517-IMX219-Add-4-lane-option-to-the-device-tree-overlay.patch b/target/linux/bcm27xx/patches-6.6/950-1517-IMX219-Add-4-lane-option-to-the-device-tree-overlay.patch new file mode 100644 index 00000000000..2872f184253 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1517-IMX219-Add-4-lane-option-to-the-device-tree-overlay.patch @@ -0,0 +1,55 @@ +From e3297f3fbffdaec8076c00167261f504bb2c64b6 Mon Sep 17 00:00:00 2001 +From: Peyton Howe +Date: Sat, 4 Jan 2025 15:15:33 -0500 +Subject: [PATCH] IMX219: Add 4-lane option to the device tree overlay + +Signed-off-by: Peyton Howe +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/imx219-overlay.dts | 17 +++++++++++++++++ + 2 files changed, 19 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2757,6 +2757,8 @@ Params: rotation Mounting + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). + vcm Configure a VCM focus drive on the sensor. ++ 4lane Enable 4 CSI2 lanes. This requires a Compute ++ Module (1, 3, 4, or 5) or Pi 5. + + + Name: imx258 +--- a/arch/arm/boot/dts/overlays/imx219-overlay.dts ++++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts +@@ -65,6 +65,22 @@ + }; + }; + ++ fragment@201 { ++ target = <&csi_ep>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ }; ++ }; ++ ++ fragment@202 { ++ target = <&cam_endpoint>; ++ __dormant__ { ++ data-lanes = <1 2 3 4>; ++ link-frequencies = ++ /bits/ 64 <363000000>; ++ }; ++ }; ++ + __overrides__ { + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; +@@ -77,6 +93,7 @@ + <&vcm>, "VANA-supply:0=", <&cam0_reg>; + vcm = <&vcm>, "status=okay", + <&cam_node>,"lens-focus:0=", <&vcm>; ++ 4lane = <0>, "+201+202"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1518-dtoverlays-waveshare-panel-Disable-new-touch-control.patch b/target/linux/bcm27xx/patches-6.6/950-1518-dtoverlays-waveshare-panel-Disable-new-touch-control.patch new file mode 100644 index 00000000000..61534982dd1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1518-dtoverlays-waveshare-panel-Disable-new-touch-control.patch @@ -0,0 +1,40 @@ +From 11381ac246576bc84dfc28f6cdd8030305c605aa Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 20 Jan 2025 11:53:04 +0000 +Subject: [PATCH] dtoverlays: waveshare-panel: Disable new touch controller by + default + +Commit e442e5c1ab6b ("arch:arm:boot:dts:overlays: Added waveshare 13.3inch +panel support") added an extra touch controller for the new panels. +On systems with old panels, it ends up spamming the kernel log as that +touch controller isn't there to respond. + +Fixes: e442e5c1ab6b ("arch:arm:boot:dts:overlays: Added waveshare 13.3inch panel support") +Signed-off-by: Dave Stevenson +--- + .../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- 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 +@@ -55,6 +55,7 @@ + touch2: ilitek@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; ++ status = "disabled"; + }; + }; + }; +@@ -125,8 +126,10 @@ + <&touch>, "touchscreen-inverted-x?", + <&touch>, "touchscreen-inverted-y?"; + 8_8_inch = <&panel>, "compatible=waveshare,8.8inch-panel"; +- 13_3_inch_4lane = <&panel>, "compatible=waveshare,13.3inch-4lane-panel"; +- 13_3_inch_2lane = <&panel>, "compatible=waveshare,13.3inch-2lane-panel"; ++ 13_3_inch_4lane = <&panel>, "compatible=waveshare,13.3inch-4lane-panel", ++ <&touch2>, "status=okay"; ++ 13_3_inch_2lane = <&panel>, "compatible=waveshare,13.3inch-2lane-panel", ++ <&touch2>, "status=okay"; + 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-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch b/target/linux/bcm27xx/patches-6.6/950-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch new file mode 100644 index 00000000000..4892c271ffc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch @@ -0,0 +1,325 @@ +From ba9883e3b667e4f1fbeacc4346f6e9179a3a5479 Mon Sep 17 00:00:00 2001 +From: Nick Hollinghurst +Date: Mon, 20 Jan 2025 11:20:48 +0000 +Subject: [PATCH] drm: rp1: rp1-dpi: Add "rgb_order" property (to match VC4 + DPI) + +As on VC4, the OF property overrides the order implied by media +bus format. Only 4 of the 6 possible orders are supported. New +add-on hardware designs should not rely on this "legacy" feature. + +Signed-off-by: Nick Hollinghurst +--- + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 15 ++ + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 8 + + drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 191 ++++++++++++++--------- + 3 files changed, 143 insertions(+), 71 deletions(-) + +--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c +@@ -292,6 +292,7 @@ static int rp1dpi_platform_probe(struct + struct device *dev = &pdev->dev; + struct rp1_dpi *dpi; + struct drm_bridge *bridge = NULL; ++ const char *rgb_order = NULL; + struct drm_panel *panel; + int i, j, ret; + +@@ -353,6 +354,20 @@ static int rp1dpi_platform_probe(struct + if (ret) + goto done_err; + ++ dpi->rgb_order_override = RP1DPI_ORDER_UNCHANGED; ++ if (!of_property_read_string(dev->of_node, "rgb_order", &rgb_order)) { ++ if (!strcmp(rgb_order, "rgb")) ++ dpi->rgb_order_override = RP1DPI_ORDER_RGB; ++ else if (!strcmp(rgb_order, "bgr")) ++ dpi->rgb_order_override = RP1DPI_ORDER_BGR; ++ else if (!strcmp(rgb_order, "grb")) ++ dpi->rgb_order_override = RP1DPI_ORDER_GRB; ++ else if (!strcmp(rgb_order, "brg")) ++ dpi->rgb_order_override = RP1DPI_ORDER_BRG; ++ else ++ DRM_ERROR("Invalid dpi order %s - ignored\n", rgb_order); ++ } ++ + /* Check if PIO can snoop on or override DPI's GPIO1 */ + dpi->gpio1_used = false; + for (i = 0; !dpi->gpio1_used; i++) { +--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h +@@ -25,6 +25,13 @@ + #define RP1DPI_CLK_PLLCORE 2 + #define RP1DPI_NUM_CLOCKS 3 + ++/* Codes (in LE byte order) used for S/W permutation */ ++#define RP1DPI_ORDER_UNCHANGED 0 ++#define RP1DPI_ORDER_RGB 0x020100 ++#define RP1DPI_ORDER_BGR 0x000102 ++#define RP1DPI_ORDER_GRB 0x020001 ++#define RP1DPI_ORDER_BRG 0x010002 ++ + /* ---------------------------------------------------------------------- */ + + struct rp1_dpi { +@@ -45,6 +52,7 @@ struct rp1_dpi { + u32 bus_fmt; + bool de_inv, clk_inv; + bool dpi_running, pipe_enabled; ++ unsigned int rgb_order_override; + struct completion finished; + + /* Experimental stuff for interlace follows */ +--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c ++++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c +@@ -223,12 +223,90 @@ int rp1dpi_hw_busy(struct rp1_dpi *dpi) + return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; + } + +-/* Table of supported input (in-memory/DMA) pixel formats. */ ++/* ++ * Table of supported input (in-memory/DMA) pixel formats. ++ * ++ * RP1 DPI describes RGB components in terms of their MS bit position, a 10-bit ++ * left-aligned bit-mask, and an optional right-shift-and-OR used for scaling. ++ * To make it easier to permute R, G and B components, we re-pack these fields ++ * into 32-bit code-words, which don't themselves correspond to any register. ++ */ ++ ++#define RGB_CODE(scale, shift, mask) (((scale) << 24) | ((shift) << 16) | (mask)) ++#define RGB_SCALE(c) ((c) >> 24) ++#define RGB_SHIFT(c) (((c) >> 16) & 31) ++#define RGB_MASK(c) ((c) & 0x3ff) ++ + struct rp1dpi_ipixfmt { +- u32 format; /* DRM format code */ +- u32 mask; /* RGB masks (10 bits each, left justified) */ +- u32 shift; /* RGB MSB positions in the memory word */ +- u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ ++ u32 format; /* DRM format code */ ++ u32 rgb_code[3]; /* (width&7), MS bit position, 10-bit mask */ ++ u32 bpp; /* Bytes per pixel minus one */ ++}; ++ ++static const struct rp1dpi_ipixfmt my_formats[] = { ++ { ++ .format = DRM_FORMAT_XRGB8888, ++ .rgb_code = { ++ RGB_CODE(0, 23, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 7, 0x3fc), ++ }, ++ .bpp = 3, ++ }, ++ { ++ .format = DRM_FORMAT_XBGR8888, ++ .rgb_code = { ++ RGB_CODE(0, 7, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 23, 0x3fc), ++ }, ++ .bpp = 3, ++ }, ++ { ++ .format = DRM_FORMAT_ARGB8888, ++ .rgb_code = { ++ RGB_CODE(0, 23, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 7, 0x3fc), ++ }, ++ .bpp = 3, ++ }, ++ { ++ .format = DRM_FORMAT_ABGR8888, ++ .rgb_code = { ++ RGB_CODE(0, 7, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 23, 0x3fc), ++ }, ++ .bpp = 3, ++ }, ++ { ++ .format = DRM_FORMAT_RGB888, ++ .rgb_code = { ++ RGB_CODE(0, 23, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 7, 0x3fc), ++ }, ++ .bpp = 2, ++ }, ++ { ++ .format = DRM_FORMAT_BGR888, ++ .rgb_code = { ++ RGB_CODE(0, 7, 0x3fc), ++ RGB_CODE(0, 15, 0x3fc), ++ RGB_CODE(0, 23, 0x3fc), ++ }, ++ .bpp = 2, ++ }, ++ { ++ .format = DRM_FORMAT_RGB565, ++ .rgb_code = { ++ RGB_CODE(5, 15, 0x3e0), ++ RGB_CODE(6, 10, 0x3f0), ++ RGB_CODE(5, 4, 0x3e0), ++ }, ++ .bpp = 1, ++ }, + }; + + #define IMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_IMASK_R_MASK, r) | \ +@@ -244,63 +322,13 @@ struct rp1dpi_ipixfmt { + FIELD_PREP_CONST(DPI_DMA_SHIFT_OG_MASK, g) | \ + FIELD_PREP_CONST(DPI_DMA_SHIFT_OB_MASK, b)) + +-static const struct rp1dpi_ipixfmt my_formats[] = { +- { +- .format = DRM_FORMAT_XRGB8888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(23, 15, 7), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3), +- }, +- { +- .format = DRM_FORMAT_XBGR8888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(7, 15, 23), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3), +- }, +- { +- .format = DRM_FORMAT_ARGB8888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(23, 15, 7), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3), +- }, +- { +- .format = DRM_FORMAT_ABGR8888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(7, 15, 23), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3), +- }, +- { +- .format = DRM_FORMAT_RGB888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(23, 15, 7), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2), +- }, +- { +- .format = DRM_FORMAT_BGR888, +- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), +- .shift = ISHIFT_RGB(7, 15, 23), +- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2), +- }, +- { +- .format = DRM_FORMAT_RGB565, +- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), +- .shift = ISHIFT_RGB(15, 10, 4), +- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)), +- }, +- { +- .format = DRM_FORMAT_BGR565, +- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), +- .shift = ISHIFT_RGB(4, 10, 15), +- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) | +- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)), +- } +-}; +- ++/* ++ * Function to update *shift with output positions, and return output RGB masks. ++ * By the time we get here, RGB order has been normalized to RGB (R most significant). ++ * Note that an internal bus is 30 bits wide: bits [21:20], [11:10], [1:0] are dropped. ++ * This makes the packed RGB5656 and RGB666 formats problematic, as colour components ++ * need to straddle the gaps; we mitigate this by hijacking input masks and scaling. ++ */ + static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz) + { + switch (bus_format) { +@@ -308,6 +336,7 @@ static u32 set_output_format(u32 bus_for + if (*shift == ISHIFT_RGB(15, 10, 4)) { + /* When framebuffer is RGB565, we can output RGB565 */ + *shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0); ++ *imask = IMASK_RGB(0x3fc, 0x3fc, 0); + *rgbsz &= DPI_DMA_RGBSZ_BPP_MASK; + return OMASK_RGB(0x3fc, 0x3fc, 0); + } +@@ -322,7 +351,7 @@ static u32 set_output_format(u32 bus_for + case MEDIA_BUS_FMT_BGR666_1X18: + /* due to a HW limitation, bit-depth is effectively RGB444 */ + *shift |= OSHIFT_RGB(23, 15, 7); +- *imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0); ++ *imask = IMASK_RGB(0x3c0, 0x3c0, 0x3c0); + *rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK); + return OMASK_RGB(0x330, 0x3c0, 0x3c0); + +@@ -359,7 +388,8 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi + struct drm_display_mode const *mode) + { + u32 shift, imask, omask, rgbsz, vctrl; +- int i; ++ u32 rgb_code[3]; ++ int order, i; + + drm_info(&dpi->drm, + "in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d%s %dkHz %cH%cV%cD%cC", +@@ -373,26 +403,45 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi + de_inv ? '-' : '+', + dpi->clk_inv ? '-' : '+'); + +- /* +- * Configure all DPI/DMA block registers, except base address. +- * DMA will not actually start until a FB base address is specified +- * using rp1dpi_hw_update(). +- */ ++ /* Look up the input (in-memory) pixel format */ + for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { + if (my_formats[i].format == in_format) + break; + } + if (i >= ARRAY_SIZE(my_formats)) { + pr_err("%s: bad input format\n", __func__); +- i = 4; ++ i = ARRAY_SIZE(my_formats) - 1; + } +- if (BUS_FMT_IS_BGR(bus_format)) +- i ^= 1; +- shift = my_formats[i].shift; +- imask = my_formats[i].mask; +- rgbsz = my_formats[i].rgbsz; ++ ++ /* ++ * Although these RGB orderings refer to the output (DPI bus) format, ++ * here we permute the *input* components. After this point, "Red" ++ * will be most significant (highest numbered GPIOs), regardless ++ * of rgb_order or bus_format. This simplifies later workarounds. ++ */ ++ order = dpi->rgb_order_override; ++ if (order == RP1DPI_ORDER_UNCHANGED) ++ order = BUS_FMT_IS_BGR(bus_format) ? RP1DPI_ORDER_BGR : RP1DPI_ORDER_RGB; ++ rgb_code[0] = my_formats[i].rgb_code[order & 3]; ++ rgb_code[1] = my_formats[i].rgb_code[(order >> 8) & 3]; ++ rgb_code[2] = my_formats[i].rgb_code[(order >> 16) & 3]; ++ rgbsz = FIELD_PREP(DPI_DMA_RGBSZ_BPP_MASK, my_formats[i].bpp) | ++ FIELD_PREP(DPI_DMA_RGBSZ_R_MASK, RGB_SCALE(rgb_code[0])) | ++ FIELD_PREP(DPI_DMA_RGBSZ_G_MASK, RGB_SCALE(rgb_code[1])) | ++ FIELD_PREP(DPI_DMA_RGBSZ_B_MASK, RGB_SCALE(rgb_code[2])); ++ shift = FIELD_PREP(DPI_DMA_SHIFT_IR_MASK, RGB_SHIFT(rgb_code[0])) | ++ FIELD_PREP(DPI_DMA_SHIFT_IG_MASK, RGB_SHIFT(rgb_code[1])) | ++ FIELD_PREP(DPI_DMA_SHIFT_IB_MASK, RGB_SHIFT(rgb_code[2])); ++ imask = FIELD_PREP(DPI_DMA_IMASK_R_MASK, RGB_MASK(rgb_code[0])) | ++ FIELD_PREP(DPI_DMA_IMASK_G_MASK, RGB_MASK(rgb_code[1])) | ++ FIELD_PREP(DPI_DMA_IMASK_B_MASK, RGB_MASK(rgb_code[2])); + omask = set_output_format(bus_format, &shift, &imask, &rgbsz); + ++ /* ++ * Configure all DPI/DMA block registers, except base address. ++ * DMA will not actually start until a FB base address is specified ++ * using rp1dpi_hw_update(). ++ */ + rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask); + rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask); + rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift); diff --git a/target/linux/bcm27xx/patches-6.6/950-1522-add-ina238-to-i2c-sensors.patch b/target/linux/bcm27xx/patches-6.6/950-1522-add-ina238-to-i2c-sensors.patch new file mode 100644 index 00000000000..cc0f31d08ba --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1522-add-ina238-to-i2c-sensors.patch @@ -0,0 +1,102 @@ +From 94de19285cc9bd781394bf1aa4fb8d401aac5195 Mon Sep 17 00:00:00 2001 +From: James Sarrett +Date: Sun, 26 Jan 2025 11:29:31 -0800 +Subject: [PATCH] add ina238 to i2c-sensors + +This patch adds the ina238 device tree parameters to the i2c-sensors +overlay. The ina238 driver needs 2 configuration parameters, shut_resistor +and ti,shunt-gain in addition to it's address, so they are added as well. +--- + arch/arm/boot/dts/overlays/README | 13 ++++++++++ + .../boot/dts/overlays/i2c-sensor-common.dtsi | 26 ++++++++++++++++++- + 2 files changed, 38 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2486,11 +2486,20 @@ Params: addr Set the + ds1621 Select the Dallas Semiconductors DS1621 temp + sensor. Valid addresses 0x48-0x4f, default 0x48 + ++ gain Gain used for measuring shunt resistor current. ++ Valid values 1 or 4, default 1. (ina238 only, ++ disabled by default) ++ + hdc100x Select the Texas Instruments HDC100x temp sensor + Valid addresses 0x40-0x43, default 0x40 + + htu21 Select the HTU21 temperature and humidity sensor + ++ ina238 Select the TI INA238 power monitor. Valid ++ addresses 0x40-0x4F, default 0x40. ++ Uses parameters shunt-resistor and ++ ti,shunt-gain for configuration ++ + int_pin Set the GPIO to use for interrupts (max30102, + mpu6050 and mpu9250 only) + +@@ -2549,6 +2558,10 @@ Params: addr Set the + reset_pin GPIO to be used to reset the device (bno055 + only, disabled by default) + ++ shunt_resistor Value of shunt resistor used for current ++ measurement in uOhms. (ina238 only, disabled ++ by default) ++ + sht3x Select the Sensirion SHT3x temperature and + humidity sensors. Valid addresses 0x44-0x45, + default 0x44 +--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi +@@ -526,6 +526,27 @@ + }; + }; + ++ fragment@35 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ina238: ina238@48 { ++ compatible = "ti,ina238"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x40>; ++ /* uOhms, uint32_t */ ++ shunt-resistor = <1000>; ++ /* 1 or 4, (±40.96 mV or ±163.84 mV) */ ++ ti,shunt-gain = <1>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ + fragment@99 { + target = <&gpio>; + __dormant__ { +@@ -573,6 +594,7 @@ + bno055 = <0>,"+31"; + sht4x = <0>,"+32"; + adt7410 = <0>,"+34"; ++ ina238 = <0>,"+35"; + + addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", + <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", +@@ -582,7 +604,7 @@ + <&ms5837>,"reg:0", <&ms8607>,"reg:0", + <&mpu6050>,"reg:0", <&mpu9250>,"reg:0", + <&bno055>,"reg:0", <&sht4x>,"reg:0", +- <&bmp380>,"reg:0", <&adt7410>,"reg:0"; ++ <&bmp380>,"reg:0", <&adt7410>,"reg:0", <&ina238>,"reg:0"; + int_pin = <&int_pins>, "brcm,pins:0", + <&int_pins>, "reg:0", + <&max30102>, "interrupts:0", +@@ -590,5 +612,7 @@ + <&mpu9250>, "interrupts:0"; + no_timeout = <&jc42>, "smbus-timeout-disable?"; + reset_pin = <&bno055>,"reset-gpios:4", <0>,"+30"; ++ shunt_resistor = <&ina238>,"shunt-resistor:0"; ++ gain = <&ina238>,"ti,shunt-gain:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1524-add-shtc3-to-i2c-sensors.patch b/target/linux/bcm27xx/patches-6.6/950-1524-add-shtc3-to-i2c-sensors.patch new file mode 100644 index 00000000000..575d52241ee --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1524-add-shtc3-to-i2c-sensors.patch @@ -0,0 +1,57 @@ +From aabe16b3cdc6172618803ed7a6002d1099d306e5 Mon Sep 17 00:00:00 2001 +From: James Sarrett +Date: Sun, 26 Jan 2025 22:07:02 -0800 +Subject: [PATCH] add shtc3 to i2c-sensors + +This patch adds the shtc3 device tree parameters to the i2c-sensors +overlay. The shtc3 driver needs no other configuration parameters, as the +i2c address is permanently baked in to the silicon. +--- + arch/arm/boot/dts/overlays/README | 3 +++ + .../arm/boot/dts/overlays/i2c-sensor-common.dtsi | 16 ++++++++++++++++ + 2 files changed, 19 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2570,6 +2570,9 @@ Params: addr Set the + humidity sensors. Valid addresses 0x44-0x45, + default 0x44 + ++ shtc3 Select the Sensirion SHTC3 temperature and ++ humidity sensors. ++ + si7020 Select the Silicon Labs Si7013/20/21 humidity/ + temperature sensor + +--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi +@@ -547,6 +547,21 @@ + }; + }; + ++ fragment@36 { ++ target = <&i2cbus>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ shtc3: shtc3@70 { ++ compatible = "sensirion,shtc3"; ++ reg = <0x70>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ + fragment@99 { + target = <&gpio>; + __dormant__ { +@@ -595,6 +610,7 @@ + sht4x = <0>,"+32"; + adt7410 = <0>,"+34"; + ina238 = <0>,"+35"; ++ shtc3 = <0>,"+36"; + + addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", + <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", diff --git a/target/linux/bcm27xx/patches-6.6/950-1525-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch b/target/linux/bcm27xx/patches-6.6/950-1525-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch new file mode 100644 index 00000000000..72d73089e3c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1525-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch @@ -0,0 +1,2137 @@ +From a18d9ced4965462cb7b3b4252ada440395105308 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 23 Jan 2025 14:14:47 +0000 +Subject: [PATCH] drivers: media: pci: Update Hailo accelerator device driver + to v4.20 + +Sourced from https://github.com/hailo-ai/hailort-drivers + +Signed-off-by: Naushir Patuck +--- + .../media/pci/hailo/common/fw_validation.c | 4 +- + .../media/pci/hailo/common/fw_validation.h | 14 +- + .../pci/hailo/common/hailo_ioctl_common.h | 10 +- + drivers/media/pci/hailo/common/pcie_common.c | 175 +++-- + drivers/media/pci/hailo/common/pcie_common.h | 69 +- + drivers/media/pci/hailo/common/vdma_common.c | 70 +- + drivers/media/pci/hailo/common/vdma_common.h | 27 +- + drivers/media/pci/hailo/src/fops.c | 90 ++- + drivers/media/pci/hailo/src/nnc.c | 4 +- + drivers/media/pci/hailo/src/pcie.c | 630 ++++++++++++++++-- + drivers/media/pci/hailo/src/pcie.h | 39 +- + drivers/media/pci/hailo/src/soc.c | 18 +- + drivers/media/pci/hailo/utils/compact.h | 8 + + drivers/media/pci/hailo/vdma/memory.c | 86 ++- + drivers/media/pci/hailo/vdma/memory.h | 2 + + 15 files changed, 997 insertions(+), 249 deletions(-) + +--- a/drivers/media/pci/hailo/common/fw_validation.c ++++ b/drivers/media/pci/hailo/common/fw_validation.c +@@ -41,8 +41,8 @@ int FW_VALIDATION__validate_fw_header(ui + 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; ++ case HAILO_BOARD_TYPE_HAILO15L: ++ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15L; + break; + default: + err = -EINVAL; +--- a/drivers/media/pci/hailo/common/fw_validation.h ++++ b/drivers/media/pci/hailo/common/fw_validation.h +@@ -9,15 +9,9 @@ + #include "hailo_ioctl_common.h" + #include + +-#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0) +-#define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB) +-#define FIRMWARE_HEADER_MAGIC_PLUTO (0xF94739AB) +- +-#ifndef HAILO_EMULATOR +-#define FIRMWARE_WAIT_TIMEOUT_MS (5000) +-#else /* ifndef HAILO_EMULATOR */ +-#define FIRMWARE_WAIT_TIMEOUT_MS (500000) +-#endif /* ifndef HAILO_EMULATOR */ ++#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0) ++#define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB) ++#define FIRMWARE_HEADER_MAGIC_HAILO15L (0xF94739AB) + + typedef enum { + FIRMWARE_HEADER_VERSION_INITIAL = 0, +@@ -61,4 +55,4 @@ int FW_VALIDATION__validate_fw_header(ui + int FW_VALIDATION__validate_cert_header(uintptr_t firmware_base_address, + size_t firmware_size, u32 *outer_consumed_firmware_offset, secure_boot_certificate_header_t **out_firmware_cert); + +-#endif +\ No newline at end of file ++#endif +--- a/drivers/media/pci/hailo/common/hailo_ioctl_common.h ++++ b/drivers/media/pci/hailo/common/hailo_ioctl_common.h +@@ -7,7 +7,7 @@ + #define _HAILO_IOCTL_COMMON_H_ + + #define HAILO_DRV_VER_MAJOR 4 +-#define HAILO_DRV_VER_MINOR 19 ++#define HAILO_DRV_VER_MINOR 20 + #define HAILO_DRV_VER_REVISION 0 + + #define _STRINGIFY_EXPANDED( x ) #x +@@ -22,6 +22,7 @@ + #define MAX_VDMA_ENGINES (3) + #define SIZE_OF_VDMA_DESCRIPTOR (16) + #define VDMA_DEST_CHANNELS_START (16) ++#define MAX_SG_DESCS_COUNT (64 * 1024u) + + #define HAILO_VDMA_MAX_ONGOING_TRANSFERS (128) + #define HAILO_VDMA_MAX_ONGOING_TRANSFERS_MASK (HAILO_VDMA_MAX_ONGOING_TRANSFERS - 1) +@@ -38,6 +39,10 @@ + #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) ++// HRT-15790 TODO: separate nnc interrupts and soc interrupts ++#define FW_ACCESS_SOFT_RESET_SHIFT (3) ++#define FW_ACCESS_SOFT_RESET_MASK (1 << FW_ACCESS_SOFT_RESET_SHIFT) ++ + #define FW_ACCESS_SOC_CONTROL_SHIFT (3) + #define FW_ACCESS_SOC_CONTROL_MASK (1 << FW_ACCESS_SOC_CONTROL_SHIFT) + +@@ -184,7 +189,6 @@ enum hailo_dma_data_direction { + }; + + // 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, +@@ -399,7 +403,7 @@ struct hailo_d2h_notification { + enum hailo_board_type { + HAILO_BOARD_TYPE_HAILO8 = 0, + HAILO_BOARD_TYPE_HAILO15, +- HAILO_BOARD_TYPE_PLUTO, ++ HAILO_BOARD_TYPE_HAILO15L, + HAILO_BOARD_TYPE_HAILO10H, + HAILO_BOARD_TYPE_HAILO10H_LEGACY, + HAILO_BOARD_TYPE_COUNT, +--- a/drivers/media/pci/hailo/common/pcie_common.c ++++ b/drivers/media/pci/hailo/common/pcie_common.c +@@ -30,6 +30,8 @@ + + #define ATR0_PCIE_BRIDGE_OFFSET (0x700) + ++#define ATR_PCIE_BRIDGE_OFFSET(atr_index) (ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20)) ++ + #define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000) + #define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x20000) + +@@ -40,17 +42,21 @@ + + #define PCIE_CONFIG_VENDOR_OFFSET (0x0098) + +-#define HAILO_PCIE_HOST_DMA_DATA_ID (0) + #define HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK (1 << 4) + #define HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK (1 << 5) + #define HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK (0x0000FFFF) + + #define HAILO_PCIE_MAX_ATR_TABLE_INDEX (3) + +-#define MAX_FILES_PER_STAGE (4) +- + #define BOOT_STATUS_UNINITIALIZED (0x1) + ++#define PCIE_CONTROL_SECTION_ADDRESS_H8 (0x60000000) ++#define PCIE_BLOCK_ADDRESS_ATR1 (0x200000) ++ ++#define PCIE_CONFIG_PCIE_CFG_QM_ROUTING_MODE_SET(reg_offset) \ ++ (reg_offset) = (((reg_offset) & ~0x00000004L) | ((uint32_t)(1) << 2)) ++ ++ + struct hailo_fw_addresses { + u32 boot_fw_header; + u32 app_fw_code_ram_base; +@@ -58,19 +64,14 @@ struct hailo_fw_addresses { + u32 boot_cont_cert; + u32 core_code_ram_base; + u32 core_fw_header; +- u32 atr0_trsl_addr1; + u32 raise_ready_offset; + u32 boot_status; +-}; +- +-struct loading_stage { +- const struct hailo_file_batch *batch; +- u32 trigger_address; ++ u32 pcie_cfg_regs; + }; + + struct hailo_board_compatibility { + struct hailo_fw_addresses fw_addresses; +- const struct loading_stage stages[MAX_LOADING_STAGES]; ++ const struct hailo_pcie_loading_stage stages[MAX_LOADING_STAGES]; + }; + + static const struct hailo_file_batch hailo10h_files_stg1[] = { +@@ -134,13 +135,18 @@ static const struct hailo_file_batch hai + .has_core = false + }, + { +- .filename = "hailo/hailo10h/core-image-minimal-hailo10-m2.ext4.gz", ++ .filename = "hailo/hailo10h/image-fs", ++#ifndef HAILO_EMULATOR + .address = 0x88000000, ++#else ++ // TODO : HRT-15692 - merge two cases ++ .address = 0x89000000, ++#endif /* ifndef HAILO_EMULATOR */ + .max_size = 0x20000000, // Max size 512MB + .is_mandatory = true, + .has_header = false, + .has_core = false +- }, ++ } + }; + + // If loading linux from EMMC - only need few files from second batch (u-boot-spl.bin and u-boot-tfa.itb) +@@ -173,7 +179,7 @@ static const struct hailo_file_batch hai + + static const struct hailo_file_batch hailo8_files_stg1[] = { + { +- .filename = "hailo/hailo8_fw.4.19.0.bin", ++ .filename = "hailo/hailo8_fw.bin", + .address = 0x20000, + .max_size = 0x50000, + .is_mandatory = true, +@@ -225,9 +231,10 @@ static const struct hailo_file_batch hai + } + }; + +-static const struct hailo_file_batch pluto_files_stg1[] = { ++// TODO HRT-15014 - Fix names for hailo15l legacy accelerator ++static const struct hailo_file_batch hailo15l_files_stg1[] = { + { +- .filename = "hailo/pluto_fw.bin", ++ .filename = "hailo/hailo15l_fw.bin", + .address = 0x20000, + .max_size = 0x100000, + .is_mandatory = true, +@@ -253,14 +260,15 @@ static const struct hailo_board_compatib + .app_fw_code_ram_base = 0x60000, + .core_code_ram_base = 0xC0000, + .core_fw_header = 0xA0000, +- .atr0_trsl_addr1 = 0x60000000, + .raise_ready_offset = 0x1684, + .boot_status = 0xe0000, + }, + .stages = { + { + .batch = hailo8_files_stg1, +- .trigger_address = 0xE0980 ++ .trigger_address = 0xE0980, ++ .timeout = FIRMWARE_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 3 + }, + }, + }, +@@ -272,14 +280,15 @@ static const struct hailo_board_compatib + .app_fw_code_ram_base = 0x20000, + .core_code_ram_base = 0x60000, + .core_fw_header = 0xC0000, +- .atr0_trsl_addr1 = 0x000BE000, + .raise_ready_offset = 0x1754, + .boot_status = 0x80000, + }, + .stages = { + { + .batch = hailo10h_legacy_files_stg1, +- .trigger_address = 0x88c98 ++ .trigger_address = 0x88c98, ++ .timeout = FIRMWARE_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 1 + }, + }, + }, +@@ -291,28 +300,34 @@ static const struct hailo_board_compatib + .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, ++ .pcie_cfg_regs = 0x002009dc, + }, + .stages = { + { + .batch = hailo10h_files_stg1, +- .trigger_address = 0x88c98 ++ .trigger_address = 0x88c98, ++ .timeout = FIRMWARE_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 3 + }, + { + .batch = hailo10h_files_stg2, +- .trigger_address = 0x84000000 ++ .trigger_address = 0x84000000, ++ .timeout = PCI_EP_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 4 + }, + { + .batch = hailo10h_files_stg2_linux_in_emmc, +- .trigger_address = 0x84000000 ++ .trigger_address = 0x84000000, ++ .timeout = FIRMWARE_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 2 + }, + }, + }, + // 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] = { ++ [HAILO_BOARD_TYPE_HAILO15L] = { + .fw_addresses = { + .boot_fw_header = 0x88000, + .boot_key_cert = 0x88018, +@@ -320,44 +335,54 @@ static const struct hailo_board_compatib + .app_fw_code_ram_base = 0x20000, + .core_code_ram_base = 0x60000, + .core_fw_header = 0xC0000, +- .atr0_trsl_addr1 = 0x000BE000, + // NOTE: After they update hw consts - check register fw_access_interrupt_w1s of pcie_config + .raise_ready_offset = 0x174c, + .boot_status = 0x80000, + }, + .stages = { + { +- .batch = pluto_files_stg1, +- .trigger_address = 0x88c98 ++ .batch = hailo15l_files_stg1, ++ .trigger_address = 0x88c98, ++ .timeout = FIRMWARE_WAIT_TIMEOUT_MS, ++ .amount_of_files_in_stage = 1 + }, + }, + } + }; + ++const struct hailo_pcie_loading_stage *hailo_pcie_get_loading_stage_info(enum hailo_board_type board_type, ++ enum loading_stages stage) ++{ ++ return &compat[board_type].stages[stage]; ++} ++ ++static u32 read_and_clear_reg(struct hailo_resource *resource, u32 offset) ++{ ++ u32 value = hailo_resource_read32(resource, offset); ++ if (value != 0) { ++ hailo_resource_write32(resource, offset, value); ++ } ++ return value; ++} + + bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source) + { +- u32 channel_data_source = 0; +- u32 channel_data_dest = 0; ++ u32 istatus_host = 0; + memset(source, 0, sizeof(*source)); + +- source->interrupt_bitmask = hailo_resource_read32(&resources->config, BCS_ISTATUS_HOST); +- if (0 == source->interrupt_bitmask) { ++ istatus_host = read_and_clear_reg(&resources->config, BCS_ISTATUS_HOST); ++ if (0 == istatus_host) { + return false; + } + +- // clear signal +- hailo_resource_write32(&resources->config, BCS_ISTATUS_HOST, source->interrupt_bitmask); ++ source->sw_interrupts = (istatus_host >> BCS_ISTATUS_HOST_SW_IRQ_SHIFT); + +- if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK) { +- channel_data_source = hailo_resource_read32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL); +- hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, channel_data_source); +- } +- if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK) { +- channel_data_dest = hailo_resource_read32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL); +- hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, channel_data_dest); ++ if (istatus_host & BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK) { ++ source->vdma_channels_bitmap |= read_and_clear_reg(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL); ++ } ++ if (istatus_host & BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK) { ++ source->vdma_channels_bitmap |= read_and_clear_reg(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL); + } +- source->vdma_channels_bitmap = channel_data_source | channel_data_dest; + + return true; + } +@@ -419,6 +444,15 @@ void hailo_pcie_write_firmware_driver_sh + hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, fw_access_value); + } + ++void hailo_pcie_write_firmware_soft_reset(struct hailo_pcie_resources *resources) ++{ ++ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses); ++ const u32 fw_access_value = FW_ACCESS_SOFT_RESET_MASK; ++ ++ // Write shutdown flag to FW ++ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, fw_access_value); ++} ++ + int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index) + { + size_t offset = 0; +@@ -431,7 +465,7 @@ int hailo_pcie_configure_atr_table(struc + }; + + BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); +- offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ offset = ATR_PCIE_BRIDGE_OFFSET(atr_index); + + return hailo_resource_write_buffer(bridge_config, offset, sizeof(atr), (void*)&atr); + } +@@ -441,7 +475,7 @@ void hailo_pcie_read_atr_table(struct ha + size_t offset = 0; + + BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index); +- offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20); ++ offset = ATR_PCIE_BRIDGE_OFFSET(atr_index); + + hailo_resource_read_buffer(bridge_config, offset, sizeof(*atr), (void*)atr); + } +@@ -510,7 +544,7 @@ static void read_memory(struct hailo_pci + hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX); + + if (base_address != src) { +- // Data is not aligned, write the first chunk ++ // Data is not aligned, read the first chunk + chunk_len = min((u32)(base_address + ATR_TABLE_SIZE - src), len); + read_memory_chunk(resources, base_address, (u32)(src - base_address), dest, chunk_len); + offset += chunk_len; +@@ -526,6 +560,18 @@ static void read_memory(struct hailo_pci + (((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX); + } + ++// Note: This function use for enabling the vDMA transaction host<->device by read modify write of the EP registers in the SOC - for fast boot over vDMA. ++void hailo_pcie_configure_ep_registers_for_dma_transaction(struct hailo_pcie_resources *resources) ++{ ++ u32 reg_routing_mercury = 0; ++ ++ BUG_ON(compat[resources->board_type].fw_addresses.pcie_cfg_regs == 0); ++ ++ read_memory(resources, compat[resources->board_type].fw_addresses.pcie_cfg_regs, ®_routing_mercury, sizeof(reg_routing_mercury)); ++ PCIE_CONFIG_PCIE_CFG_QM_ROUTING_MODE_SET(reg_routing_mercury); ++ write_memory(resources, compat[resources->board_type].fw_addresses.pcie_cfg_regs, ®_routing_mercury, sizeof(reg_routing_mercury)); ++} ++ + static void hailo_write_app_firmware(struct hailo_pcie_resources *resources, firmware_header_t *fw_header, + secure_boot_certificate_header_t *fw_cert) + { +@@ -551,11 +597,11 @@ static void hailo_write_core_firmware(st + write_memory(resources, fw_addresses->core_fw_header, fw_header, sizeof(firmware_header_t)); + } + +-void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 address) ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 stage) + { + u32 pcie_finished = 1; + +- write_memory(resources, address, (void*)&pcie_finished, sizeof(pcie_finished)); ++ write_memory(resources, compat[resources->board_type].stages[stage].trigger_address, (void*)&pcie_finished, sizeof(pcie_finished)); + } + + u32 hailo_get_boot_status(struct hailo_pcie_resources *resources) +@@ -673,16 +719,14 @@ static int write_single_file(struct hail + + 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; ++ const struct hailo_pcie_loading_stage *stage_info = hailo_pcie_get_loading_stage_info(resources->board_type, stage); ++ const struct hailo_file_batch *files_batch = stage_info->batch; ++ const u8 amount_of_files = stage_info->amount_of_files_in_stage; + int file_index = 0; + int err = 0; + +- for (file_index = 0; file_index < MAX_FILES_PER_STAGE; file_index++) ++ for (file_index = 0; file_index < amount_of_files; 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); +@@ -696,31 +740,29 @@ int hailo_pcie_write_firmware_batch(stru + dev_notice(dev, "File %s written successfully\n", files_batch[file_index].filename); + } + +- hailo_trigger_firmware_boot(resources, compat[resources->board_type].stages[stage].trigger_address); ++ hailo_trigger_firmware_boot(resources, stage); + + return 0; + } + +-// TODO: HRT-14147 - remove this function +-static bool hailo_pcie_is_device_ready_for_boot(struct hailo_pcie_resources *resources) +-{ +- return hailo_get_boot_status(resources) == BOOT_STATUS_UNINITIALIZED; +-} +- + bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources) + { + u32 offset; + u32 atr_value; + +- // TODO: HRT-14147 +- if (HAILO_BOARD_TYPE_HAILO10H == resources->board_type) { +- return !hailo_pcie_is_device_ready_for_boot(resources); ++ if (HAILO_BOARD_TYPE_HAILO8 == resources->board_type) { ++ offset = ATR_PCIE_BRIDGE_OFFSET(0) + offsetof(struct hailo_atr_config, atr_trsl_addr_1); ++ atr_value = hailo_resource_read32(&resources->config, offset); ++ ++ return (PCIE_CONTROL_SECTION_ADDRESS_H8 == atr_value); + } ++ else { ++ offset = ATR_PCIE_BRIDGE_OFFSET(1) + offsetof(struct hailo_atr_config, atr_trsl_addr_1); ++ atr_value = hailo_resource_read32(&resources->config, offset); + +- offset = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1); +- atr_value = hailo_resource_read32(&resources->config, offset); ++ return (PCIE_BLOCK_ADDRESS_ATR1 == atr_value); ++ } + +- return atr_value == compat[resources->board_type].fw_addresses.atr0_trsl_addr1; + } + + bool hailo_pcie_wait_for_firmware(struct hailo_pcie_resources *resources) +@@ -764,8 +806,7 @@ 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 | BCS_ISTATUS_SOC_CONNECT_ACCEPTED | BCS_ISTATUS_SOC_CLOSED_IRQ); ++ mask |= BCS_ISTATUS_HOST_SW_IRQ_MASK; + hailo_resource_write32(&resources->config, BSC_IMASK_HOST, mask); + } + +@@ -822,7 +863,7 @@ int hailo_set_device_type(struct hailo_p + switch(resources->board_type) { + case HAILO_BOARD_TYPE_HAILO8: + case HAILO_BOARD_TYPE_HAILO10H_LEGACY: +- case HAILO_BOARD_TYPE_PLUTO: ++ case HAILO_BOARD_TYPE_HAILO15L: + resources->accelerator_type = HAILO_ACCELERATOR_TYPE_NNC; + break; + case HAILO_BOARD_TYPE_HAILO10H: +--- a/drivers/media/pci/hailo/common/pcie_common.h ++++ b/drivers/media/pci/hailo/common/pcie_common.h +@@ -18,11 +18,8 @@ + #include + + +-#define BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK (0x04000000) +-#define BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION (0x02000000) +-#define BCS_ISTATUS_HOST_DRIVER_DOWN (0x08000000) +-#define BCS_ISTATUS_SOC_CONNECT_ACCEPTED (0x10000000) +-#define BCS_ISTATUS_SOC_CLOSED_IRQ (0x20000000) ++#define BCS_ISTATUS_HOST_SW_IRQ_MASK (0xFF000000) ++#define BCS_ISTATUS_HOST_SW_IRQ_SHIFT (24) + #define BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK (0x000000FF) + #define BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK (0x0000FF00) + +@@ -36,13 +33,19 @@ + #define HAILO_PCIE_FW_ACCESS_BAR (4) + + #define HAILO_PCIE_DMA_ENGINES_COUNT (1) ++#define PCI_VDMA_ENGINE_INDEX (0) ++ ++#define MAX_FILES_PER_STAGE (4) ++ ++#define HAILO_PCIE_HOST_DMA_DATA_ID (0) ++#define HAILO_PCI_EP_HOST_DMA_DATA_ID (6) + + #define DRIVER_NAME "hailo" + + #define PCI_VENDOR_ID_HAILO 0x1e60 + #define PCI_DEVICE_ID_HAILO_HAILO8 0x2864 +-#define PCI_DEVICE_ID_HAILO_HAILO15 0x45C4 +-#define PCI_DEVICE_ID_HAILO_PLUTO 0x43a2 ++#define PCI_DEVICE_ID_HAILO_HAILO10H 0x45C4 ++#define PCI_DEVICE_ID_HAILO_HAILO15L 0x43a2 + + typedef u64 hailo_ptr_t; + +@@ -69,18 +72,24 @@ enum loading_stages { + MAX_LOADING_STAGES = 3 + }; + +-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, +- SOC_CLOSED_IRQ = BCS_ISTATUS_SOC_CLOSED_IRQ, +- VDMA_SRC_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK, +- VDMA_DEST_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK ++enum hailo_pcie_nnc_sw_interrupt_masks { ++ HAILO_PCIE_NNC_FW_NOTIFICATION_IRQ = 0x2, ++ HAILO_PCIE_NNC_FW_CONTROL_IRQ = 0x4, ++ HAILO_PCIE_NNC_DRIVER_DOWN_IRQ = 0x8, ++}; ++ ++enum hailo_pcie_soc_sw_interrupt_masks { ++ HAILO_PCIE_SOC_CONTROL_IRQ = 0x10, ++ HAILO_PCIE_SOC_CLOSE_IRQ = 0x20, ++}; ++ ++enum hailo_pcie_boot_interrupt_masks { ++ HAILO_PCIE_BOOT_SOFT_RESET_IRQ = 0x1, ++ HAILO_PCIE_BOOT_IRQ = 0x2, + }; + + struct hailo_pcie_interrupt_source { +- u32 interrupt_bitmask; ++ u32 sw_interrupts; + u32 vdma_channels_bitmap; + }; + +@@ -93,6 +102,13 @@ struct hailo_file_batch { + bool has_core; + }; + ++struct hailo_pcie_loading_stage { ++ const struct hailo_file_batch *batch; ++ u32 trigger_address; ++ u32 timeout; ++ u8 amount_of_files_in_stage; ++}; ++ + // TODO: HRT-6144 - Align Windows/Linux to QNX + #ifdef __QNX__ + enum hailo_bar_index { +@@ -117,8 +133,23 @@ enum hailo_bar_index { + extern "C" { + #endif + ++ ++#ifndef HAILO_EMULATOR ++#define TIME_UNTIL_REACH_BOOTLOADER (10) ++#define PCI_EP_WAIT_TIMEOUT_MS (40000) ++#define FIRMWARE_WAIT_TIMEOUT_MS (5000) ++#else /* ifndef HAILO_EMULATOR */ ++// PCI EP timeout is defined to 50000000 because on Emulator the boot time + linux init time can be very long (4+ hours) ++#define TIME_UNTIL_REACH_BOOTLOADER (10000) ++#define PCI_EP_WAIT_TIMEOUT_MS (50000000) ++#define FIRMWARE_WAIT_TIMEOUT_MS (5000000) ++#endif /* ifndef HAILO_EMULATOR */ ++ + extern struct hailo_vdma_hw hailo_pcie_vdma_hw; + ++const struct hailo_pcie_loading_stage* hailo_pcie_get_loading_stage_info(enum hailo_board_type board_type, ++ enum loading_stages stage); ++ + // Reads the interrupt source from BARs, return false if there is no interrupt. + // note - this function clears the interrupt signals. + bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source); +@@ -137,7 +168,9 @@ 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 hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 address); ++void hailo_pcie_write_firmware_soft_reset(struct hailo_pcie_resources *resources); ++void hailo_pcie_configure_ep_registers_for_dma_transaction(struct hailo_pcie_resources *resources); ++void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 stage); + + int hailo_set_device_type(struct hailo_pcie_resources *resources); + +@@ -157,4 +190,4 @@ void hailo_pcie_soc_read_response(struct + } + #endif + +-#endif /* _HAILO_COMMON_PCIE_COMMON_H_ */ +\ No newline at end of file ++#endif /* _HAILO_COMMON_PCIE_COMMON_H_ */ +--- a/drivers/media/pci/hailo/common/vdma_common.c ++++ b/drivers/media/pci/hailo/common/vdma_common.c +@@ -15,16 +15,6 @@ + #include + #include + +- +-#define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5) +- +-#define CHANNEL_CONTROL_OFFSET (0x0) +-#define CHANNEL_DEPTH_ID_OFFSET (0x1) +-#define CHANNEL_NUM_AVAIL_OFFSET (0x2) +-#define CHANNEL_NUM_PROC_OFFSET (0x4) +-#define CHANNEL_ERROR_OFFSET (0x8) +-#define CHANNEL_DEST_REGS_OFFSET (0x10) +- + #define VDMA_CHANNEL_CONTROL_START (0x1) + #define VDMA_CHANNEL_CONTROL_ABORT (0b00) + #define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10) +@@ -160,17 +150,17 @@ static u8 get_channel_id(u8 channel_inde + return (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE) ? (channel_index & 0xF) : INVALID_VDMA_CHANNEL; + } + +-static int program_descriptors_in_chunk( ++int hailo_vdma_program_descriptors_in_chunk( + struct hailo_vdma_hw *vdma_hw, + dma_addr_t chunk_addr, + unsigned int chunk_size, + struct hailo_vdma_descriptors_list *desc_list, + u32 desc_index, + u32 max_desc_index, +- u8 channel_id) ++ u8 channel_index, ++ u8 data_id) + { + const u16 page_size = desc_list->desc_page_size; +- const u8 ddr_data_id = vdma_hw->ddr_data_id; + const u32 descs_to_program = DIV_ROUND_UP(chunk_size, page_size); + const u32 starting_desc_index = desc_index; + const u32 residue_size = chunk_size % page_size; +@@ -187,7 +177,7 @@ static int program_descriptors_in_chunk( + return -ERANGE; + } + +- encoded_addr = vdma_hw->hw_ops.encode_desc_dma_address_range(chunk_addr, chunk_addr + chunk_size, page_size, channel_id); ++ encoded_addr = vdma_hw->hw_ops.encode_desc_dma_address_range(chunk_addr, chunk_addr + chunk_size, page_size, get_channel_id(channel_index)); + if (INVALID_VDMA_ADDRESS == encoded_addr) { + return -EFAULT; + } +@@ -197,7 +187,7 @@ static int program_descriptors_in_chunk( + // 'desc_index & desc_list_len_mask' is used instead of modulo; see hailo_vdma_descriptors_list documentation. + hailo_vdma_program_descriptor( + &desc_list->desc_list[desc_index & desc_list->desc_count_mask], +- encoded_addr, page_size, ddr_data_id); ++ encoded_addr, page_size, data_id); + encoded_addr += page_size; + } + +@@ -205,7 +195,7 @@ static int program_descriptors_in_chunk( + // 'desc_index & desc_list_len_mask' is used instead of modulo; see hailo_vdma_descriptors_list documentation. + dma_desc = &desc_list->desc_list[desc_index & desc_list->desc_count_mask]; + hailo_vdma_program_descriptor(dma_desc, encoded_addr, +- (residue_size == 0) ? page_size : (u16)residue_size, ddr_data_id); ++ (residue_size == 0) ? page_size : (u16)residue_size, data_id); + + return (int)descs_to_program; + } +@@ -241,7 +231,6 @@ static int bind_and_program_descriptors_ + enum hailo_vdma_interrupts_domain last_desc_interrupts, + bool is_debug) + { +- const u8 channel_id = get_channel_id(channel_index); + int desc_programmed = 0; + int descs_programmed_in_chunk = 0; + u32 max_desc_index = 0; +@@ -279,8 +268,8 @@ static int bind_and_program_descriptors_ + (u32)(sg_dma_len(sg_entry)); + chunk_size = min((u32)program_size, chunk_size); + +- descs_programmed_in_chunk = program_descriptors_in_chunk(vdma_hw, chunk_start_addr, chunk_size, desc_list, +- starting_desc, max_desc_index, channel_id); ++ descs_programmed_in_chunk = hailo_vdma_program_descriptors_in_chunk(vdma_hw, chunk_start_addr, chunk_size, desc_list, ++ starting_desc, max_desc_index, channel_index, vdma_hw->ddr_data_id); + if (descs_programmed_in_chunk < 0) { + return descs_programmed_in_chunk; + } +@@ -363,16 +352,16 @@ static int validate_channel_state(struct + return 0; + } + +-static void set_num_avail(u8 __iomem *host_regs, u16 num_avail) ++void hailo_vdma_set_num_avail(u8 __iomem *regs, u16 num_avail) + { +- u32 host_regs_val = ioread32(host_regs); +- iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_val, num_avail), +- host_regs); ++ u32 regs_val = ioread32(regs); ++ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, regs_val, num_avail), ++ regs); + } + +-static u16 get_num_proc(u8 __iomem *host_regs) ++u16 hailo_vdma_get_num_proc(u8 __iomem *regs) + { +- return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET)); ++ return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(regs + CHANNEL_NUM_PROC_OFFSET)); + } + + int hailo_vdma_launch_transfer( +@@ -455,7 +444,7 @@ int hailo_vdma_launch_transfer( + + new_num_avail = (u16)((last_desc + 1) % desc_list->desc_count); + channel->state.num_avail = new_num_avail; +- set_num_avail(channel->host_regs, new_num_avail); ++ hailo_vdma_set_num_avail(channel->host_regs, new_num_avail); + + return (int)total_descs; + } +@@ -463,7 +452,7 @@ int hailo_vdma_launch_transfer( + static void hailo_vdma_push_timestamp(struct hailo_vdma_channel *channel) + { + struct hailo_channel_interrupt_timestamp_list *timestamp_list = &channel->timestamp_list; +- const u16 num_proc = get_num_proc(channel->host_regs); ++ const u16 num_proc = hailo_vdma_get_num_proc(channel->host_regs); + if (TIMESTAMPS_CIRC_SPACE(*timestamp_list) != 0) { + timestamp_list->timestamps[timestamp_list->head].timestamp_ns = ktime_get_ns(); + timestamp_list->timestamps[timestamp_list->head].desc_num_processed = num_proc; +@@ -725,7 +714,7 @@ int hailo_vdma_engine_fill_irq_data(stru + // the actual hw_num_processed is a number between 1 and desc_count. + // Therefore the value can be desc_count, in this case we change it to + // zero. +- hw_num_proc = get_num_proc(channel->host_regs) & channel->state.desc_count_mask; ++ hw_num_proc = hailo_vdma_get_num_proc(channel->host_regs) & channel->state.desc_count_mask; + + while (ONGOING_TRANSFERS_CIRC_CNT(channel->ongoing_transfers) > 0) { + struct hailo_ongoing_transfer *cur_transfer = +@@ -780,12 +769,13 @@ static void hailo_vdma_channel_abort(u8 + VDMA_CHANNEL_CONTROL_ABORT), host_regs); + } + +-int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, ++int hailo_vdma_start_channel(u8 __iomem *regs, uint64_t desc_dma_address, uint32_t desc_count, + uint8_t data_id) + { + u16 dma_address_l = 0; + u32 dma_address_h = 0; + u32 desc_depth_data_id = 0; ++ u8 desc_depth = ceil_log2(desc_count); + + if (((desc_dma_address & 0xFFFF) != 0) || + (desc_depth > DESCRIPTOR_LIST_MAX_DEPTH)) { +@@ -798,22 +788,22 @@ int hailo_vdma_start_channel(u8 __iomem + } + + // Stop old channel state +- hailo_vdma_stop_channel(host_regs); ++ hailo_vdma_stop_channel(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); ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET) * BITS_IN_BYTE, ioread32(regs + ++ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET), dma_address_l), 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); ++ iowrite32(dma_address_h, 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); ++ iowrite32(desc_depth_data_id, regs); + +- start_vdma_control_register(host_regs); ++ start_vdma_control_register(regs); + + return 0; + } +@@ -853,10 +843,10 @@ static int hailo_vdma_wait_until_channel + return -ETIMEDOUT; + } + +-void hailo_vdma_stop_channel(u8 __iomem *host_regs) ++void hailo_vdma_stop_channel(u8 __iomem *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)); ++ u8 host_side_channel_regs = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(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) +@@ -866,17 +856,17 @@ void hailo_vdma_stop_channel(u8 __iomem + // 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); ++ hailo_vdma_channel_pause(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); ++ err = hailo_vdma_wait_until_channel_idle(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); ++ hailo_vdma_channel_abort(regs); + } + + bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel) +--- a/drivers/media/pci/hailo/common/vdma_common.h ++++ b/drivers/media/pci/hailo/common/vdma_common.h +@@ -16,6 +16,15 @@ + #define VDMA_DESCRIPTOR_LIST_ALIGN (1 << 16) + #define INVALID_VDMA_ADDRESS (0) + ++#define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5) ++ ++#define CHANNEL_CONTROL_OFFSET (0x0) ++#define CHANNEL_DEPTH_ID_OFFSET (0x1) ++#define CHANNEL_NUM_AVAIL_OFFSET (0x2) ++#define CHANNEL_NUM_PROC_OFFSET (0x4) ++#define CHANNEL_ERROR_OFFSET (0x8) ++#define CHANNEL_DEST_REGS_OFFSET (0x10) ++ + #ifdef __cplusplus + extern "C" + { +@@ -172,6 +181,20 @@ int hailo_vdma_program_descriptors_list( + enum hailo_vdma_interrupts_domain last_desc_interrupts, + bool is_debug); + ++int hailo_vdma_program_descriptors_in_chunk( ++ struct hailo_vdma_hw *vdma_hw, ++ dma_addr_t chunk_addr, ++ unsigned int chunk_size, ++ struct hailo_vdma_descriptors_list *desc_list, ++ u32 desc_index, ++ u32 max_desc_index, ++ u8 channel_index, ++ u8 data_id); ++ ++void hailo_vdma_set_num_avail(u8 __iomem *regs, u16 num_avail); ++ ++u16 hailo_vdma_get_num_proc(u8 __iomem *regs); ++ + /** + * Launch a transfer on some vdma channel. Includes: + * 1. Binding the transfer buffers to the descriptors list. +@@ -249,9 +272,9 @@ 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); ++int hailo_vdma_start_channel(u8 __iomem *regs, uint64_t desc_dma_address, uint32_t desc_count, uint8_t data_id); + +-void hailo_vdma_stop_channel(u8 __iomem *host_regs); ++void hailo_vdma_stop_channel(u8 __iomem *regs); + + bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel); + +--- a/drivers/media/pci/hailo/src/fops.c ++++ b/drivers/media/pci/hailo/src/fops.c +@@ -294,6 +294,54 @@ static void firmware_notification_irq_ha + } + } + ++static void boot_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source) ++{ ++ if (irq_source->sw_interrupts & HAILO_PCIE_BOOT_SOFT_RESET_IRQ) { ++ hailo_dbg(board, "soft reset trigger IRQ\n"); ++ complete(&board->soft_reset.reset_completed); ++ } ++ if (irq_source->sw_interrupts & HAILO_PCIE_BOOT_IRQ) { ++ hailo_dbg(board, "boot trigger IRQ\n"); ++ complete_all(&board->fw_boot.fw_loaded_completion); ++ } else { ++ board->fw_boot.boot_used_channel_bitmap &= ~irq_source->vdma_channels_bitmap; ++ hailo_dbg(board, "boot vDMA data IRQ - channel_bitmap = 0x%x\n", irq_source->vdma_channels_bitmap); ++ if (0 == board->fw_boot.boot_used_channel_bitmap) { ++ complete_all(&board->fw_boot.vdma_boot_completion); ++ hailo_dbg(board, "boot vDMA data trigger IRQ\n"); ++ } ++ } ++} ++ ++static void nnc_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source) ++{ ++ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_FW_CONTROL_IRQ) { ++ complete(&board->nnc.fw_control.completion); ++ } ++ ++ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_DRIVER_DOWN_IRQ) { ++ complete(&board->driver_down.reset_completed); ++ } ++ ++ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_FW_NOTIFICATION_IRQ) { ++ firmware_notification_irq_handler(board); ++ } ++} ++ ++static void soc_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source) ++{ ++ if (irq_source->sw_interrupts & HAILO_PCIE_SOC_CONTROL_IRQ) { ++ complete_all(&board->soc.control_resp_ready); ++ } ++ ++ if (irq_source->sw_interrupts & HAILO_PCIE_SOC_CLOSE_IRQ) { ++ hailo_info(board, "soc_irq_handler - HAILO_PCIE_SOC_CLOSE_IRQ\n"); ++ // always use bitmap=0xFFFFFFFF - it is ok to wake all interrupts since each handler will check if the stream was aborted or not. ++ hailo_vdma_wakeup_interrupts(&board->vdma, &board->vdma.vdma_engines[DEFAULT_VDMA_ENGINE_INDEX], ++ 0xFFFFFFFF); ++ } ++} ++ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + irqreturn_t hailo_irqhandler(int irq, void *dev_id, struct pt_regs *regs) + #else +@@ -320,39 +368,21 @@ irqreturn_t hailo_irqhandler(int irq, vo + + return_value = IRQ_HANDLED; + +- // wake fw_control if needed +- if (irq_source.interrupt_bitmask & FW_CONTROL) { +- complete(&board->nnc.fw_control.completion); +- } +- +- // wake driver_down if needed +- if (irq_source.interrupt_bitmask & DRIVER_DOWN) { +- complete(&board->driver_down.reset_completed); +- } +- +- if (irq_source.interrupt_bitmask & FW_NOTIFICATION) { +- if (!completion_done(&board->fw_loaded_completion)) { +- // Complete firmware loaded completion +- complete_all(&board->fw_loaded_completion); ++ if (board->fw_boot.is_in_boot) { ++ boot_irq_handler(board, &irq_source); ++ } else { ++ if (HAILO_ACCELERATOR_TYPE_NNC == board->pcie_resources.accelerator_type) { ++ nnc_irq_handler(board, &irq_source); ++ } else if (HAILO_ACCELERATOR_TYPE_SOC == board->pcie_resources.accelerator_type) { ++ soc_irq_handler(board, &irq_source); + } else { +- firmware_notification_irq_handler(board); ++ hailo_err(board, "Invalid accelerator type %d\n", board->pcie_resources.accelerator_type); + } +- } +- +- if (irq_source.interrupt_bitmask & SOC_CONNECT_ACCEPTED) { +- complete_all(&board->soc.control_resp_ready); +- } + +- if (irq_source.interrupt_bitmask & SOC_CLOSED_IRQ) { +- hailo_info(board, "hailo_irqhandler - SOC_CLOSED_IRQ\n"); +- // always use bitmap=0xFFFFFFFF - it is ok to wake all interrupts since each handler will check if the stream was aborted or not. +- hailo_vdma_wakeup_interrupts(&board->vdma, &board->vdma.vdma_engines[DEFAULT_VDMA_ENGINE_INDEX], +- 0xFFFFFFFF); +- } +- +- if (0 != irq_source.vdma_channels_bitmap) { +- hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX, +- irq_source.vdma_channels_bitmap); ++ if (0 != irq_source.vdma_channels_bitmap) { ++ hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX, ++ irq_source.vdma_channels_bitmap); ++ } + } + } + +--- a/drivers/media/pci/hailo/src/nnc.c ++++ b/drivers/media/pci/hailo/src/nnc.c +@@ -148,8 +148,8 @@ static long hailo_read_notification_ioct + + // Check if was disabled + if (current_waiting_thread->is_disabled) { +- hailo_info(board, "HAILO_READ_NOTIFICATION, can't find notification wait for tgid=%d\n", current->tgid); +- err = -EINVAL; ++ hailo_info(board, "HAILO_READ_NOTIFICATION - notification disabled for tgid=%d\n", current->tgid); ++ err = -ECANCELED; + goto l_exit; + } + +--- a/drivers/media/pci/hailo/src/pcie.c ++++ b/drivers/media/pci/hailo/src/pcie.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) + #include +@@ -29,6 +30,7 @@ + #include "utils/logs.h" + #include "utils/compact.h" + #include "vdma/vdma.h" ++#include "vdma/memory.h" + + #if LINUX_VERSION_CODE < KERNEL_VERSION( 5, 4, 0 ) + #include +@@ -46,8 +48,9 @@ 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; ++static bool force_hailo10h_legacy_mode = false; + static bool force_boot_linux_from_eemc = false; ++static bool support_soft_reset = true; + + #define DEVICE_NODE_NAME "hailo" + static int char_major = 0; +@@ -291,12 +294,468 @@ static void hailo_pcie_remove_board(stru + up(&g_hailo_add_board_mutex); + } + +-static bool wait_for_firmware_completion(struct completion *fw_load_completion) ++/** ++ * Wait until the relevant completion is done. ++ * ++ * @param completion - pointer to the completion struct to wait for. ++ * @param msecs - the amount of time to wait in milliseconds. ++ * @return false if timed out, true if completed. ++ */ ++static bool wait_for_firmware_completion(struct completion *completion, unsigned int msecs) ++{ ++ return (0 != wait_for_completion_timeout(completion, msecs_to_jiffies(msecs))); ++} ++ ++/** ++ * Program one FW file descriptors to the vDMA engine. ++ * ++ * @param dev - pointer to the device struct we are working on. ++ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources. ++ * @param file_address - the address of the file in the device memory. ++ * @param transfer_buffer - the buffer to program to the vDMA engine. ++ * @param channel_index - the index of the channel to program. ++ * @param filename - the name of the file to program. ++ * @param raise_int_on_completion - true if this is the last descriptors chunk in the specific channel in the boot flow, false otherwise. If true - will enable ++ * an IRQ for the relevant channel when the transfer is finished. ++ * @return the amount of descriptors programmed on success, negative error code on failure. ++ */ ++static int pcie_vdma_program_one_file_descriptors(struct device *dev, struct hailo_pcie_boot_dma_channel_state *boot_channel_state, ++ u32 file_address, struct hailo_vdma_mapped_transfer_buffer transfer_buffer, u8 channel_index, const char *filename, bool raise_int_on_completion) ++{ ++ int device_desc = 0, host_desc = 0; ++ enum hailo_vdma_interrupts_domain interrupts_domain = raise_int_on_completion ? HAILO_VDMA_INTERRUPTS_DOMAIN_HOST : ++ HAILO_VDMA_INTERRUPTS_DOMAIN_NONE; ++ ++ hailo_dev_dbg(dev, "channel_index = %d, file_name = %s, file_address = 0x%x, transfer_buffer.offset = 0x%x,\ ++ size_to_program = 0x%x, starting_desc/desc_index = 0x%x\n", channel_index, filename, file_address, ++ transfer_buffer.offset, transfer_buffer.size, boot_channel_state->desc_program_num); ++ ++ // program descriptors ++ device_desc = hailo_vdma_program_descriptors_in_chunk(&hailo_pcie_vdma_hw, file_address, transfer_buffer.size, ++ &boot_channel_state->device_descriptors_buffer.desc_list, boot_channel_state->desc_program_num, ++ (boot_channel_state->device_descriptors_buffer.desc_list.desc_count - 1), channel_index, HAILO_PCI_EP_HOST_DMA_DATA_ID); ++ if (device_desc < 0) { ++ hailo_dev_err(dev, "Failed to program device descriptors, error = %u\n", device_desc); ++ return device_desc; ++ } ++ ++ host_desc = hailo_vdma_program_descriptors_list(&hailo_pcie_vdma_hw, &boot_channel_state->host_descriptors_buffer.desc_list, ++ boot_channel_state->desc_program_num, &transfer_buffer, true, channel_index, interrupts_domain, false); ++ if (host_desc < 0) { ++ hailo_dev_err(dev, "Failed to program host descriptors, error = %u\n", host_desc); ++ return host_desc; ++ } ++ ++ // checks that same amount of decsriptors were programmed on device side and host side ++ if (host_desc != device_desc) { ++ hailo_dev_err(dev, "Host and device descriptors should be the same\n"); ++ return -EINVAL; ++ } ++ ++ return host_desc; ++} ++ ++/** ++ * Program one FW file to the vDMA engine. ++ * ++ * @param board - pointer to the board struct we are working on. ++ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources. ++ * @param file_address - the address of the file in the device memory. ++ * @param filename - the name of the file to program. ++ * @param raise_int_on_completion - true if this is the last file in the boot flow, false otherwise. uses to enable an IRQ for the ++ * relevant channel when the transfer is finished. ++ * @return 0 on success, negative error code on failure. at the end of the function the firmware is released. ++ */ ++static int pcie_vdma_program_one_file(struct hailo_pcie_board *board, struct hailo_pcie_boot_dma_state *boot_dma_state, u32 file_address, ++ const char *filename, bool raise_int_on_completion) ++{ ++ const struct firmware *firmware = NULL; ++ struct hailo_vdma_mapped_transfer_buffer transfer_buffer = {0}; ++ int desc_programmed = 0; ++ int err = 0; ++ size_t bytes_copied = 0, remaining_size = 0, data_offset = 0, desc_num_left = 0, current_desc_to_program = 0; ++ ++ hailo_notice(board, "Programing file %s for dma transfer\n", filename); ++ ++ // load firmware directly without usermode helper for the relevant file ++ err = request_firmware_direct(&firmware, filename, board->vdma.dev); ++ if (err < 0) { ++ hailo_err(board, "Failed to allocate memory for file %s\n", filename); ++ return err; ++ } ++ ++ // set the remaining size as the whole file size to begin with ++ remaining_size = firmware->size; ++ ++ while (remaining_size > 0) { ++ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[boot_dma_state->curr_channel_index]; ++ bool is_last_desc_chunk_of_curr_channel = false; ++ bool rais_interrupt_on_last_chunk = false; ++ ++ hailo_dbg(board, "desc_program_num = 0x%x, desc_page_size = 0x%x, on channel = %d\n", ++ channel->desc_program_num, HAILO_PCI_OVER_VDMA_PAGE_SIZE, boot_dma_state->curr_channel_index); ++ ++ // increment the channel index if the current channel is full ++ if ((MAX_SG_DESCS_COUNT - 1) == channel->desc_program_num) { ++ boot_dma_state->curr_channel_index++; ++ channel = &boot_dma_state->channels[boot_dma_state->curr_channel_index]; ++ board->fw_boot.boot_used_channel_bitmap |= (1 << boot_dma_state->curr_channel_index); ++ } ++ ++ // calculate the number of descriptors left to program and the number of bytes left to program ++ desc_num_left = (MAX_SG_DESCS_COUNT - 1) - channel->desc_program_num; ++ ++ // prepare the transfer buffer to make sure all the fields are initialized ++ transfer_buffer.sg_table = &channel->sg_table; ++ transfer_buffer.size = min(remaining_size, (desc_num_left * HAILO_PCI_OVER_VDMA_PAGE_SIZE)); ++ // no need to check for overflow since the variables are constant and always desc_program_num <= max u16 (65536) ++ // & the buffer max size is 256 Mb << 4G (max u32) ++ transfer_buffer.offset = (channel->desc_program_num * HAILO_PCI_OVER_VDMA_PAGE_SIZE); ++ ++ // check if this is the last descriptor chunk to program in the whole boot flow ++ current_desc_to_program = (transfer_buffer.size / HAILO_PCI_OVER_VDMA_PAGE_SIZE); ++ is_last_desc_chunk_of_curr_channel = ((MAX_SG_DESCS_COUNT - 1) == ++ (current_desc_to_program + channel->desc_program_num)); ++ rais_interrupt_on_last_chunk = (is_last_desc_chunk_of_curr_channel || (raise_int_on_completion && ++ (remaining_size == transfer_buffer.size))); ++ ++ // try to copy the file to the buffer, if failed, release the firmware and return ++ bytes_copied = sg_pcopy_from_buffer(transfer_buffer.sg_table->sgl, transfer_buffer.sg_table->orig_nents, ++ &firmware->data[data_offset], transfer_buffer.size, transfer_buffer.offset); ++ if (transfer_buffer.size != bytes_copied) { ++ hailo_err(board, "There is not enough memory allocated to copy file %s\n", filename); ++ release_firmware(firmware); ++ return -EFBIG; ++ } ++ ++ // program the descriptors ++ desc_programmed = pcie_vdma_program_one_file_descriptors(&board->pDev->dev, channel, (file_address + data_offset), ++ transfer_buffer, boot_dma_state->curr_channel_index, filename, rais_interrupt_on_last_chunk); ++ if (desc_programmed < 0) { ++ hailo_err(board, "Failed to program descriptors for file %s, on cahnnel = %d\n", filename, ++ boot_dma_state->curr_channel_index); ++ release_firmware(firmware); ++ return desc_programmed; ++ } ++ ++ // Update remaining size, data_offset and desc_program_num for the next iteration ++ remaining_size -= transfer_buffer.size; ++ data_offset += transfer_buffer.size; ++ channel->desc_program_num += desc_programmed; ++ } ++ ++ hailo_notice(board, "File %s programed successfully\n", filename); ++ ++ release_firmware(firmware); ++ ++ return desc_programmed; ++} ++ ++/** ++ * Program the entire batch of firmware files to the vDMA engine. ++ * ++ * @param board - pointer to the board struct we are working on. ++ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources. ++ * @param resources - pointer to the hailo_pcie_resources struct. ++ * @param stage - the stage to program. ++ * @return 0 on success, negative error code on failure. ++ */ ++static long pcie_vdma_program_entire_batch(struct hailo_pcie_board *board, struct hailo_pcie_boot_dma_state *boot_dma_state, ++ struct hailo_pcie_resources *resources, u32 stage) ++{ ++ long err = 0; ++ int file_index = 0; ++ const struct hailo_pcie_loading_stage *stage_info = hailo_pcie_get_loading_stage_info(resources->board_type, stage); ++ const struct hailo_file_batch *files_batch = stage_info->batch; ++ const u8 amount_of_files = stage_info->amount_of_files_in_stage; ++ const char *filename = NULL; ++ u32 file_address = 0; ++ ++ for (file_index = 0; file_index < amount_of_files; file_index++) ++ { ++ filename = files_batch[file_index].filename; ++ file_address = files_batch[file_index].address; ++ ++ if (NULL == filename) { ++ hailo_err(board, "The amount of files wasn't specified for stage %d\n", stage); ++ break; ++ } ++ ++ err = pcie_vdma_program_one_file(board, boot_dma_state, file_address, filename, ++ (file_index == (amount_of_files - 1))); ++ if (err < 0) { ++ hailo_err(board, "Failed to program file %s\n", filename); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * Release noncontinuous memory (virtual continuous memory). (sg table and kernel_addrs) ++ * ++ * @param dev - pointer to the device struct we are working on. ++ * @param sg_table - the sg table to release. ++ * @param kernel_addrs - the kernel address to release. ++ */ ++static void pcie_vdma_release_noncontinuous_memory(struct device *dev, struct sg_table *sg_table, void *kernel_addrs) ++{ ++ dma_unmap_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE); ++ sg_free_table(sg_table); ++ vfree(kernel_addrs); ++} ++ ++/** ++ * Allocate noncontinuous memory (virtual continuous memory). ++ * ++ * @param dev - pointer to the device struct we are working on. ++ * @param buffer_size - the size of the buffer to allocate. ++ * @param kernel_addrs - pointer to the allocated buffer. ++ * @param sg_table - pointer to the sg table struct. ++ * @return 0 on success, negative error code on failure. on failure all resurces are released. (pages array, sg table, kernel_addrs) ++ */ ++static long pcie_vdma_allocate_noncontinuous_memory(struct device *dev, u64 buffer_size, void **kernel_addrs, struct sg_table *sg_table) ++{ ++ struct page **pages = NULL; ++ size_t npages = 0; ++ struct scatterlist *sgl = NULL; ++ long err = 0; ++ size_t i = 0; ++ ++ // allocate noncontinuous memory for the kernel address (virtual continuous memory) ++ *kernel_addrs = vmalloc(buffer_size); ++ if (NULL == *kernel_addrs) { ++ hailo_dev_err(dev, "Failed to allocate memory for kernel_addrs\n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ // map the memory to pages ++ npages = DIV_ROUND_UP(buffer_size, PAGE_SIZE); ++ ++ // allocate memory for a virtually contiguous array for the pages ++ pages = kvmalloc_array(npages, sizeof(*pages), GFP_KERNEL); ++ if (!pages) { ++ err = -ENOMEM; ++ hailo_dev_err(dev, "Failed to allocate memory for pages\n"); ++ goto release_user_addrs; ++ } ++ ++ // walk a vmap address to the struct page it maps ++ for (i = 0; i < npages; i++) { ++ pages[i] = vmalloc_to_page(*kernel_addrs + (i * PAGE_SIZE)); ++ if (!pages[i]) { ++ err = -ENOMEM; ++ hailo_dev_err(dev, "Failed to get page from vmap address\n"); ++ goto release_array; ++ } ++ } ++ ++ // allocate and initialize the sg table from a list of pages ++ sgl = sg_alloc_table_from_pages_segment_compat(sg_table, pages, npages, 0, buffer_size, SGL_MAX_SEGMENT_SIZE, NULL, ++ 0, GFP_KERNEL); ++ if (IS_ERR(sgl)) { ++ err = PTR_ERR(sgl); ++ hailo_dev_err(dev, "sg table alloc failed (err %ld)..\n", err); ++ goto release_array; ++ } ++ ++ // map the sg list ++ sg_table->nents = dma_map_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE); ++ if (0 == sg_table->nents) { ++ hailo_dev_err(dev, "failed to map sg list for user buffer\n"); ++ err = -ENXIO; ++ goto release_sg_table; ++ } ++ ++ // clean exit - just release the pages array & return err = 0 ++ err = 0; ++ kfree(pages); ++ goto exit; ++ ++release_sg_table: ++ dma_unmap_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE); ++release_array: ++ kfree(pages); ++release_user_addrs: ++ vfree(*kernel_addrs); ++exit: ++ return err; ++} ++ ++/** ++ * Release all boot resources. ++ * ++ * @param board - pointer to the board struct we are working on. ++ * @param engine - pointer to the vdma engine struct. ++ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources. ++ */ ++static void pcie_vdme_release_boot_resources(struct hailo_pcie_board *board, struct hailo_vdma_engine *engine, ++ struct hailo_pcie_boot_dma_state *boot_dma_state) ++{ ++ u8 channel_index = 0; ++ ++ // release all the resources ++ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) { ++ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[channel_index]; ++ // release descriptor lists ++ if (channel->host_descriptors_buffer.kernel_address != NULL) { ++ hailo_desc_list_release(&board->pDev->dev, &channel->host_descriptors_buffer); ++ } ++ if (channel->device_descriptors_buffer.kernel_address != NULL) { ++ hailo_desc_list_release(&board->pDev->dev, &channel->device_descriptors_buffer); ++ } ++ ++ // stops all boot vDMA channels ++ hailo_vdma_stop_channel(engine->channels[channel_index].host_regs); ++ hailo_vdma_stop_channel(engine->channels[channel_index].device_regs); ++ ++ // release noncontinuous memory (virtual continuous memory) ++ if (channel->kernel_addrs != NULL) { ++ pcie_vdma_release_noncontinuous_memory(&board->pDev->dev, &channel->sg_table, channel->kernel_addrs); ++ } ++ } ++} ++ ++/** ++ * Allocate boot resources for vDMA transfer. ++ * ++ * @param desc_page_size - the size of the descriptor page. ++ * @param board - pointer to the board struct we are working on. ++ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources. ++ * @param engine - pointer to the vDMA engine struct. ++ * @return 0 on success, negative error code on failure. in case of failure descriptor lists are released, ++ * boot vDMA channels are stopped and memory is released. ++ */ ++static long pcie_vdme_allocate_boot_resources(u32 desc_page_size, struct hailo_pcie_board *board, ++ struct hailo_pcie_boot_dma_state *boot_dma_state, struct hailo_vdma_engine *engine) ++{ ++ long err = 0; ++ uintptr_t device_handle = 0, host_handle = 0; ++ u8 channel_index = 0; ++ ++ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) { ++ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[channel_index]; ++ ++ // create 2 descriptors list - 1 for the host & 1 for the device for each channel ++ err = hailo_desc_list_create(&board->pDev->dev, MAX_SG_DESCS_COUNT, desc_page_size, host_handle, false, ++ &channel->host_descriptors_buffer); ++ if (err < 0) { ++ hailo_err(board, "failed to allocate host descriptors list buffer\n"); ++ goto release_all_resources; ++ } ++ ++ err = hailo_desc_list_create(&board->pDev->dev, MAX_SG_DESCS_COUNT, desc_page_size, device_handle, false, ++ &channel->device_descriptors_buffer); ++ if (err < 0) { ++ hailo_err(board, "failed to allocate device descriptors list buffer\n"); ++ goto release_all_resources; ++ } ++ ++ // start vDMA channels - both sides with DDR at the host side (AKA ID 0) ++ err = hailo_vdma_start_channel(engine->channels[channel_index].host_regs, ++ channel->host_descriptors_buffer.dma_address, ++ channel->host_descriptors_buffer.desc_list.desc_count, board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_err(board, "Error starting host vdma channel\n"); ++ goto release_all_resources; ++ } ++ ++ err = hailo_vdma_start_channel(engine->channels[channel_index].device_regs, ++ channel->device_descriptors_buffer.dma_address, ++ channel->device_descriptors_buffer.desc_list.desc_count, board->vdma.hw->ddr_data_id); ++ if (err < 0) { ++ hailo_err(board, "Error starting device vdma channel\n"); ++ goto release_all_resources; ++ } ++ ++ // initialize the buffer size per channel ++ channel->buffer_size = (MAX_SG_DESCS_COUNT * desc_page_size); ++ ++ // allocate noncontinuous memory (virtual continuous memory) ++ err = pcie_vdma_allocate_noncontinuous_memory(&board->pDev->dev, channel->buffer_size, &channel->kernel_addrs, ++ &channel->sg_table); ++ if (err < 0) { ++ hailo_err(board, "Failed to allocate noncontinuous memory\n"); ++ goto release_all_resources; ++ } ++ } ++ ++ return 0; ++ ++release_all_resources: ++ pcie_vdme_release_boot_resources(board, engine, boot_dma_state); ++ return err; ++} ++ ++/** ++ * Write FW boot files over vDMA using multiple channels for timing optimizations. ++ * ++ * The function is divided into the following steps: ++ * 1) Allocate resources for the boot process. ++ * 2) Programs descriptors to point to the memory and start the vDMA. ++ * 3) Waits until the vDMA is done and triggers the device to start the boot process. ++ * 4) Releases all the resources. ++ * ++ * @param board - pointer to the board struct. ++ * @param stage - the stage of the boot process. ++ * @param desc_page_size - the size of the descriptor page. ++ * @return 0 on success, negative error code on failure. in any case all resurces are released. ++ */ ++static long pcie_write_firmware_batch_over_dma(struct hailo_pcie_board *board, u32 stage, u32 desc_page_size) + { +- return (0 != wait_for_completion_timeout(fw_load_completion, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS))); ++ long err = 0; ++ struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_VDMA_ENGINE_INDEX]; ++ u8 channel_index = 0; ++ ++ err = pcie_vdme_allocate_boot_resources(desc_page_size, board, &board->fw_boot.boot_dma_state, engine); ++ if (err < 0) { ++ hailo_err(board, "Failed to create descriptors and start channels\n"); ++ return err; ++ } ++ ++ // initialize the completion for the vDMA boot data completion ++ reinit_completion(&board->fw_boot.vdma_boot_completion); ++ ++ err = pcie_vdma_program_entire_batch(board, &board->fw_boot.boot_dma_state, &board->pcie_resources, stage); ++ if (err < 0) { ++ hailo_err(board, "Failed to program entire batch\n"); ++ goto release_all; ++ } ++ ++ // sync the sg tables for the device before statirng the vDMA ++ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) { ++ dma_sync_sgtable_for_device(&board->pDev->dev, &board->fw_boot.boot_dma_state.channels[channel_index].sg_table, ++ DMA_TO_DEVICE); ++ } ++ ++ // start the vDMA transfer on all channels ++ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) { ++ struct hailo_pcie_boot_dma_channel_state *channel = &board->fw_boot.boot_dma_state.channels[channel_index]; ++ if (channel->desc_program_num != 0) { ++ hailo_vdma_set_num_avail(engine->channels[channel_index].host_regs, channel->desc_program_num); ++ hailo_vdma_set_num_avail(engine->channels[channel_index].device_regs, channel->desc_program_num); ++ hailo_dbg(board, "Set num avail to %u, on channel %u\n", channel->desc_program_num, channel_index); ++ } ++ } ++ ++ if (!wait_for_firmware_completion(&board->fw_boot.vdma_boot_completion, hailo_pcie_get_loading_stage_info(board->pcie_resources.board_type, SECOND_STAGE)->timeout)) { ++ hailo_err(board, "Timeout waiting for vDMA boot data completion\n"); ++ err = -ETIMEDOUT; ++ goto release_all; ++ } ++ ++ hailo_notice(board, "vDMA transfer completed, triggering boot\n"); ++ reinit_completion(&board->fw_boot.fw_loaded_completion); ++ hailo_trigger_firmware_boot(&board->pcie_resources, stage); ++ ++release_all: ++ pcie_vdme_release_boot_resources(board, engine, &board->fw_boot.boot_dma_state); ++ return err; + } + +-static int hailo_load_soc_firmware(struct hailo_pcie_resources *resources, ++static int load_soc_firmware(struct hailo_pcie_board *board, struct hailo_pcie_resources *resources, + struct device *dev, struct completion *fw_load_completion) + { + u32 boot_status = 0; +@@ -304,104 +763,165 @@ static int hailo_load_soc_firmware(struc + u32 second_stage = force_boot_linux_from_eemc ? SECOND_STAGE_LINUX_IN_EMMC : SECOND_STAGE; + + if (hailo_pcie_is_firmware_loaded(resources)) { +- hailo_dev_warn(dev, "Firmware batch was already loaded\n"); ++ hailo_dev_warn(dev, "SOC Firmware batch was already loaded\n"); + return 0; + } + ++ // configure the EP registers for the DMA transaction ++ hailo_pcie_configure_ep_registers_for_dma_transaction(resources); ++ + init_completion(fw_load_completion); ++ init_completion(&board->fw_boot.vdma_boot_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); ++ hailo_dev_err(dev, "Failed writing SOC FIRST_STAGE firmware files. err %d\n", err); + return err; + } + +- if (!wait_for_firmware_completion(fw_load_completion)) { ++ if (!wait_for_firmware_completion(fw_load_completion, hailo_pcie_get_loading_stage_info(resources->board_type, FIRST_STAGE)->timeout)) { + boot_status = hailo_get_boot_status(resources); +- hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ hailo_dev_err(dev, "Timeout waiting for SOC FIRST_STAGE 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); ++ reinit_completion(fw_load_completion); ++ ++ err = (int)pcie_write_firmware_batch_over_dma(board, second_stage, HAILO_PCI_OVER_VDMA_PAGE_SIZE); + if (err < 0) { +- hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ hailo_dev_err(dev, "Failed writing SOC SECOND_STAGE firmware files over vDMA. err %d\n", err); + return err; + } + +- if (!wait_for_firmware_completion(fw_load_completion)) { ++ if (!wait_for_firmware_completion(fw_load_completion, hailo_pcie_get_loading_stage_info(resources->board_type, SECOND_STAGE)->timeout)) { + boot_status = hailo_get_boot_status(resources); +- hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status); ++ hailo_dev_err(dev, "Timeout waiting for SOC SECOND_STAGE firmware file, boot status %u\n", boot_status); + return -ETIMEDOUT; + } + +- hailo_dev_notice(dev, "Firmware Batch loaded successfully\n"); ++ reinit_completion(fw_load_completion); ++ reinit_completion(&board->fw_boot.vdma_boot_completion); ++ ++ hailo_dev_notice(dev, "SOC Firmware Batch loaded successfully\n"); + + return 0; + } +- +-static int hailo_load_nnc_firmware(struct hailo_pcie_resources *resources, +- struct device *dev, struct completion *fw_load_completion) ++static int load_nnc_firmware(struct hailo_pcie_board *board) + { + u32 boot_status = 0; + int err = 0; ++ struct device *dev = &board->pDev->dev; + +- if (hailo_pcie_is_firmware_loaded(resources)) { +- hailo_dev_warn(dev, "Firmware batch was already loaded\n"); +- return 0; ++ if (hailo_pcie_is_firmware_loaded(&board->pcie_resources)) { ++ if (support_soft_reset) { ++ err = hailo_pcie_soft_reset(&board->pcie_resources, &board->soft_reset.reset_completed); // send control, wait for done ++ if (err < 0) { ++ hailo_dev_err(dev, "Failed hailo pcie soft reset. err %d\n", err); ++ return 0; ++ } ++ hailo_dev_notice(dev, "Soft reset done\n"); ++ } else { ++ hailo_dev_warn(dev, "NNC Firmware batch was already loaded\n"); ++ return 0; ++ } + } + +- init_completion(fw_load_completion); ++ init_completion(&board->fw_boot.fw_loaded_completion); + +- err = hailo_pcie_write_firmware_batch(dev, resources, FIRST_STAGE); ++ err = hailo_pcie_write_firmware_batch(dev, &board->pcie_resources, FIRST_STAGE); + if (err < 0) { +- hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err); ++ hailo_dev_err(dev, "Failed writing NNC firmware files. err %d\n", err); + return err; + } + +- 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); ++ if (!wait_for_firmware_completion(&board->fw_boot.fw_loaded_completion, hailo_pcie_get_loading_stage_info(board->pcie_resources.board_type, FIRST_STAGE)->timeout)) { ++ boot_status = hailo_get_boot_status(&board->pcie_resources); ++ hailo_dev_err(dev, "Timeout waiting for NNC firmware file, boot status %u\n", boot_status); + return -ETIMEDOUT; + } + +- hailo_dev_notice(dev, "Firmware loaded successfully\n"); ++ hailo_dev_notice(dev, "NNC Firmware loaded successfully\n"); + + return 0; + } + +-static int hailo_activate_board(struct hailo_pcie_board *board) ++int hailo_pcie_soft_reset(struct hailo_pcie_resources *resources, struct completion *reset_completed) + { ++ bool completion_result = false; + int err = 0; + +- (void)hailo_pcie_disable_aspm(board, PCIE_LINK_STATE_L0S, false); ++ hailo_pcie_write_firmware_soft_reset(resources); + +- err = hailo_enable_interrupts(board); +- if (err < 0) { +- hailo_err(board, "Failed Enabling interrupts %d\n", err); ++ reinit_completion(reset_completed); ++ ++ // Wait for response ++ completion_result = ++ wait_for_firmware_completion(reset_completed, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS)); ++ if (completion_result == false) { ++ pr_warn("hailo reset firmware, timeout waiting for shutdown response (timeout_ms=%d)\n", FIRMWARE_WAIT_TIMEOUT_MS); ++ err = -ETIMEDOUT; + return err; + } + ++ msleep(TIME_UNTIL_REACH_BOOTLOADER); ++ pr_notice("hailo_driver_down finished\n"); ++ ++ return err; ++} ++ ++static int load_firmware(struct hailo_pcie_board *board) ++{ + switch (board->pcie_resources.accelerator_type) { + case HAILO_ACCELERATOR_TYPE_SOC: +- err = hailo_load_soc_firmware(&board->pcie_resources, &board->pDev->dev, +- &board->fw_loaded_completion); +- break; ++ return load_soc_firmware(board, &board->pcie_resources, &board->pDev->dev, &board->fw_boot.fw_loaded_completion); + case HAILO_ACCELERATOR_TYPE_NNC: +- err = hailo_load_nnc_firmware(&board->pcie_resources, &board->pDev->dev, +- &board->fw_loaded_completion); +- break; ++ return load_nnc_firmware(board); + default: +- hailo_err(board, "Invalid board type"); +- err = -EINVAL; ++ hailo_err(board, "Invalid board type %d\n", board->pcie_resources.accelerator_type); ++ return -EINVAL; + } ++} ++ ++static int enable_boot_interrupts(struct hailo_pcie_board *board) ++{ ++ int err = hailo_enable_interrupts(board); + if (err < 0) { +- hailo_err(board, "Firmware load failed\n"); +- hailo_disable_interrupts(board); ++ hailo_err(board, "Failed enabling interrupts %d\n", err); + return err; + } + ++ board->fw_boot.is_in_boot = true; ++ return 0; ++} ++ ++static void disable_boot_interrupts(struct hailo_pcie_board *board) ++{ ++ board->fw_boot.is_in_boot = false; + hailo_disable_interrupts(board); ++} ++ ++static int hailo_activate_board(struct hailo_pcie_board *board) ++{ ++ int err = 0; ++ ktime_t start_time = 0, end_time = 0; ++ ++ (void)hailo_pcie_disable_aspm(board, PCIE_LINK_STATE_L0S, false); ++ ++ err = enable_boot_interrupts(board); ++ if (err < 0) { ++ return err; ++ } ++ ++ start_time = ktime_get(); ++ err = load_firmware(board); ++ end_time = ktime_get(); ++ hailo_notice(board, "FW loaded, took %lld ms\n", ktime_to_ms(ktime_sub(end_time, start_time))); ++ disable_boot_interrupts(board); ++ ++ if (err < 0) { ++ hailo_err(board, "Firmware load failed\n"); ++ return err; ++ } + + if (power_mode_enabled()) { + // Setting the device to low power state, until the user opens the device +@@ -520,12 +1040,9 @@ static int pcie_resources_init(struct pc + } + + +- // 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) { ++ if (HAILO_BOARD_TYPE_HAILO10H == board_type){ ++ if (true == force_hailo10h_legacy_mode) { + board_type = HAILO_BOARD_TYPE_HAILO10H_LEGACY; +- } else { +- board_type = HAILO_BOARD_TYPE_HAILO10H; + } + } + +@@ -696,7 +1213,8 @@ static int hailo_pcie_probe(struct pci_d + } + + pBoard->interrupts_enabled = false; +- init_completion(&pBoard->fw_loaded_completion); ++ pBoard->fw_boot.is_in_boot = false; ++ init_completion(&pBoard->fw_boot.fw_loaded_completion); + + sema_init(&pBoard->mutex, 1); + atomic_set(&pBoard->ref_count, 0); +@@ -707,6 +1225,7 @@ static int hailo_pcie_probe(struct pci_d + hailo_soc_init(&pBoard->soc); + + init_completion(&pBoard->driver_down.reset_completed); ++ init_completion(&pBoard->soft_reset.reset_completed); + + memset(&pBoard->memory_transfer_params, 0, sizeof(pBoard->memory_transfer_params)); + +@@ -724,6 +1243,10 @@ static int hailo_pcie_probe(struct pci_d + goto probe_release_pcie_resources; + } + ++ // Initialize the boot channel bitmap to 1 since channel 0 is always used for boot ++ // (we will always use at least 1 channel which is LSB in the bitmap) ++ pBoard->fw_boot.boot_used_channel_bitmap = (1 << 0); ++ memset(&pBoard->fw_boot.boot_dma_state, 0, sizeof(pBoard->fw_boot.boot_dma_state)); + err = hailo_activate_board(pBoard); + if (err < 0) { + hailo_err(pBoard, "Failed activating board %d\n", err); +@@ -927,8 +1450,8 @@ static const struct pci_error_handlers h + static struct pci_device_id hailo_pcie_id_table[] = + { + {PCI_DEVICE_DATA(HAILO, HAILO8, HAILO_BOARD_TYPE_HAILO8)}, +- {PCI_DEVICE_DATA(HAILO, HAILO15, HAILO_BOARD_TYPE_HAILO15)}, +- {PCI_DEVICE_DATA(HAILO, PLUTO, HAILO_BOARD_TYPE_PLUTO)}, ++ {PCI_DEVICE_DATA(HAILO, HAILO10H, HAILO_BOARD_TYPE_HAILO10H)}, ++ {PCI_DEVICE_DATA(HAILO, HAILO15L, HAILO_BOARD_TYPE_HAILO15L)}, + {0,0,0,0,0,0,0 }, + }; + +@@ -1024,12 +1547,15 @@ 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_param(force_hailo10h_legacy_mode, bool, S_IRUGO); ++MODULE_PARM_DESC(force_hailo10h_legacy_mode, "Forces work with Hailo10h in legacy mode(relevant for emulators)"); + + module_param(force_boot_linux_from_eemc, bool, S_IRUGO); + MODULE_PARM_DESC(force_boot_linux_from_eemc, "Boot the linux image from eemc (Requires special Image)"); + ++module_param(support_soft_reset, bool, S_IRUGO); ++MODULE_PARM_DESC(support_soft_reset, "enables driver reload to reload a new firmware as well"); ++ + 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 +@@ -19,6 +19,9 @@ + + #include + ++#define HAILO_PCI_OVER_VDMA_NUM_CHANNELS (8) ++#define HAILO_PCI_OVER_VDMA_PAGE_SIZE (512) ++ + struct hailo_fw_control_info { + // protects that only one fw control will be send at a time + struct semaphore mutex; +@@ -33,6 +36,11 @@ struct hailo_pcie_driver_down_info { + struct completion reset_completed; + }; + ++struct hailo_pcie_soft_reset { ++ // called from the interrupt handler to notify that FW completed reset ++ struct completion reset_completed; ++}; ++ + struct hailo_fw_boot { + // the filp that enabled interrupts for fw boot. the interrupt is enabled if this is not null + struct file *filp; +@@ -64,6 +72,32 @@ struct hailo_file_context { + u32 soc_used_channels_bitmap; + }; + ++struct hailo_pcie_boot_dma_channel_state { ++ struct hailo_descriptors_list_buffer host_descriptors_buffer; ++ struct hailo_descriptors_list_buffer device_descriptors_buffer; ++ struct sg_table sg_table; ++ u64 buffer_size; ++ void *kernel_addrs; ++ u32 desc_program_num; ++}; ++ ++struct hailo_pcie_boot_dma_state { ++ struct hailo_pcie_boot_dma_channel_state channels[HAILO_PCI_OVER_VDMA_NUM_CHANNELS]; ++ u8 curr_channel_index; ++}; ++ ++struct hailo_pcie_fw_boot { ++ struct hailo_pcie_boot_dma_state boot_dma_state; ++ // is_in_boot is set to true when the board is in boot mode ++ bool is_in_boot; ++ // boot_used_channel_bitmap is a bitmap of the channels that are used for boot ++ u16 boot_used_channel_bitmap; ++ // fw_loaded_completion is used to notify that the FW was loaded - SOC & NNC ++ struct completion fw_loaded_completion; ++ // vdma_boot_completion is used to notify that the vDMA boot data was transferred completely on all used channels for boot ++ struct completion vdma_boot_completion; ++}; ++ + struct hailo_pcie_board { + struct list_head board_list; + struct pci_dev *pDev; +@@ -74,13 +108,15 @@ struct hailo_pcie_board { + struct hailo_pcie_nnc nnc; + struct hailo_pcie_soc soc; + struct hailo_pcie_driver_down_info driver_down; ++ struct hailo_pcie_soft_reset soft_reset; + struct semaphore mutex; + struct hailo_vdma_controller vdma; + ++ struct hailo_pcie_fw_boot fw_boot; ++ + struct hailo_memory_transfer_params memory_transfer_params; + u32 desc_max_page_size; + enum hailo_allocation_mode allocation_mode; +- struct completion fw_loaded_completion; + bool interrupts_enabled; + }; + +@@ -89,6 +125,7 @@ bool power_mode_enabled(void); + struct hailo_pcie_board* hailo_pcie_get_board_index(u32 index); + void hailo_disable_interrupts(struct hailo_pcie_board *board); + int hailo_enable_interrupts(struct hailo_pcie_board *board); ++int hailo_pcie_soft_reset(struct hailo_pcie_resources *resources, struct completion *reset_completed); + + #endif /* _HAILO_PCI_PCIE_H_ */ + +--- a/drivers/media/pci/hailo/src/soc.c ++++ b/drivers/media/pci/hailo/src/soc.c +@@ -12,12 +12,15 @@ + #include "vdma_common.h" + #include "utils/logs.h" + #include "vdma/memory.h" ++#include "pcie_common.h" + + #include + +-#define PCI_SOC_VDMA_ENGINE_INDEX (0) ++#ifndef HAILO_EMULATOR + #define PCI_SOC_CONTROL_CONNECT_TIMEOUT_MS (1000) +-#define PCI_SOC_INPUT_CHANNEL_BITMASK (0x000000FF) ++#else ++#define PCI_SOC_CONTROL_CONNECT_TIMEOUT_MS (1000000) ++#endif /* ifndef HAILO_EMULATOR */ + + void hailo_soc_init(struct hailo_pcie_soc *soc) + { +@@ -84,10 +87,9 @@ long hailo_soc_connect_ioctl(struct hail + 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 = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ struct hailo_vdma_engine *vdma_engine = &controller->vdma_engines[PCI_VDMA_ENGINE_INDEX]; + 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; + + if (copy_from_user(¶ms, (void *)arg, sizeof(params))) { +@@ -136,9 +138,8 @@ long hailo_soc_connect_ioctl(struct hail + } + + // 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, ++ err = hailo_vdma_start_channel(input_channel->host_regs, input_descriptors_buffer->dma_address, input_descriptors_buffer->desc_list.desc_count, + 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); +@@ -149,9 +150,8 @@ long hailo_soc_connect_ioctl(struct hail + hailo_set_bit(params.input_channel_index, &context->soc_used_channels_bitmap); + + // 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, ++ err = hailo_vdma_start_channel(output_channel->host_regs, output_descriptors_buffer->dma_address, output_descriptors_buffer->desc_list.desc_count, + 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); +@@ -175,7 +175,7 @@ static int close_channels(struct hailo_p + { + struct hailo_pcie_soc_request request = {0}; + struct hailo_pcie_soc_response response = {0}; +- struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX]; ++ struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_VDMA_ENGINE_INDEX]; + struct hailo_vdma_channel *channel = NULL; + u8 channel_index = 0; + +--- a/drivers/media/pci/hailo/utils/compact.h ++++ b/drivers/media/pci/hailo/utils/compact.h +@@ -48,6 +48,14 @@ static inline long get_user_pages_compac + } + #endif + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0) ++static inline void dma_sync_sgtable_for_device(struct device *dev, ++ struct sg_table *sgt, enum dma_data_direction dir) ++{ ++ dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, dir); ++} ++#endif ++ + #ifndef _LINUX_MMAP_LOCK_H + static inline void mmap_read_lock(struct mm_struct *mm) + { +--- a/drivers/media/pci/hailo/vdma/memory.c ++++ b/drivers/media/pci/hailo/vdma/memory.c +@@ -14,10 +14,10 @@ + #include + #include + +- +-#define SGL_MAX_SEGMENT_SIZE (0x10000) + // See linux/mm.h + #define MMIO_AND_NO_PAGES_VMA_MASK (VM_IO | VM_PFNMAP) ++// The linux kernel names the dmabuf's vma vm_file field "dmabuf" ++#define VMA_VM_FILE_DMABUF_NAME ("dmabuf") + + static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma, + struct sg_table *sgt); +@@ -27,10 +27,16 @@ static void clear_sg_table(struct sg_tab + + #if LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0) ++#define DMA_NS_NAME DMA_BUF ++#else ++#define DMA_NS_NAME "DMA_BUF" ++#endif // LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + // Import DMA_BUF namespace for needed kernels +-MODULE_IMPORT_NS(DMA_BUF); +-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) */ ++MODULE_IMPORT_NS(DMA_NS_NAME); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 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) +@@ -103,6 +109,39 @@ static void hailo_unmap_dmabuf(struct ha + + #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */ + ++// Function that checks if the vma is backed by a mapped dmabuf ++static bool is_dmabuf_vma(struct vm_area_struct *vma) ++{ ++ return (vma && vma->vm_file && (0 == strcmp(vma->vm_file->f_path.dentry->d_name.name, VMA_VM_FILE_DMABUF_NAME))); ++} ++ ++static int create_fd_from_vma(struct device *dev, struct vm_area_struct *vma) { ++ struct file *file = NULL; ++ int fd = 0; ++ ++ if (!vma || !vma->vm_file) { ++ dev_err(dev, "Invalid VMA or no associated file.\n"); ++ return -EINVAL; ++ } ++ ++ file = vma->vm_file; ++ ++ // This functions increments the ref count of the file ++ get_file(file); ++ ++ // 0 for default flags ++ fd = get_unused_fd_flags(0); ++ if (fd < 0) { ++ dev_err(dev, "Failed to get unused file descriptor.\n"); ++ fput(file); ++ return fd; ++ } ++ ++ // Install the file into the file descriptor table ++ fd_install(fd, file); ++ return fd; ++} ++ + 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) +@@ -112,7 +151,8 @@ struct hailo_vdma_buffer *hailo_vdma_buf + struct sg_table sgt = {0}; + struct vm_area_struct *vma = NULL; + bool is_mmio = false; +- struct hailo_dmabuf_info dmabuf_info = {0}; ++ struct hailo_dmabuf_info dmabuf_info = {0}; ++ bool created_dmabuf_fd_from_vma = false; + + mapped_buffer = kzalloc(sizeof(*mapped_buffer), GFP_KERNEL); + if (NULL == mapped_buffer) { +@@ -121,12 +161,27 @@ struct hailo_vdma_buffer *hailo_vdma_buf + goto cleanup; + } + +- if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && (HAILO_DMA_DMABUF_BUFFER != buffer_type)) { ++ if (HAILO_DMA_DMABUF_BUFFER != buffer_type) { + vma = find_vma(current->mm, user_address); +- if (NULL == vma) { +- dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size); +- ret = -EFAULT; +- goto cleanup; ++ if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING)) { ++ if (NULL == vma) { ++ dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size); ++ ret = -EFAULT; ++ goto cleanup; ++ } ++ } ++ ++ if (is_dmabuf_vma(vma)) { ++ dev_dbg(dev, "Given vma is backed by dmabuf - creating fd and mapping as dmabuf\n"); ++ buffer_type = HAILO_DMA_DMABUF_BUFFER; ++ ret = create_fd_from_vma(dev, vma); ++ if (ret < 0) { ++ dev_err(dev, "Failed creating fd from vma in given dmabuf\n"); ++ goto cleanup; ++ } ++ // Override user address with fd to the dmabuf - like normal dmabuf flow ++ user_address = ret; ++ created_dmabuf_fd_from_vma = true; + } + } + +@@ -157,6 +212,11 @@ struct hailo_vdma_buffer *hailo_vdma_buf + dev_err(dev, "Failed mapping dmabuf\n"); + goto cleanup; + } ++ // If created dmabuf fd from vma need to decrement refcount and release fd ++ if (created_dmabuf_fd_from_vma) { ++ fput(vma->vm_file); ++ put_unused_fd(user_address); ++ } + } else { + // user_address is a standard 'struct page' backed memory address + ret = prepare_sg_table(&sgt, user_address, size, low_mem_driver_allocated_buffer); +@@ -331,7 +391,7 @@ int hailo_desc_list_create(struct device + dev_err(dev, "Failed to allocate descriptors list, desc_count 0x%x, buffer_size 0x%zx, This failure means there is not a sufficient amount of CMA memory " + "(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficient memory.\n", + descriptors_count, buffer_size); +- return -ENOMEM; ++ return -ENOBUFS; + } + + descriptors->buffer_size = buffer_size; +@@ -467,7 +527,7 @@ int hailo_vdma_continuous_buffer_alloc(s + if (NULL == kernel_address) { + dev_warn(dev, "Failed to allocate continuous buffer, size 0x%zx. This failure means there is not a sufficient amount of CMA memory " + "(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficent memory.\n", size); +- return -ENOMEM; ++ return -ENOBUFS; + } + + continuous_buffer->kernel_address = kernel_address; +--- a/drivers/media/pci/hailo/vdma/memory.h ++++ b/drivers/media/pci/hailo/vdma/memory.h +@@ -11,6 +11,8 @@ + + #include "vdma/vdma.h" + ++#define SGL_MAX_SEGMENT_SIZE (0x10000) ++ + 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); diff --git a/target/linux/bcm27xx/patches-6.6/950-1526-overlays-Regularisation-and-improvements.patch b/target/linux/bcm27xx/patches-6.6/950-1526-overlays-Regularisation-and-improvements.patch new file mode 100644 index 00000000000..c763b1d27a5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1526-overlays-Regularisation-and-improvements.patch @@ -0,0 +1,139 @@ +From fa71765fd3c98fa170407e72e052004913da6874 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 27 Jan 2025 14:17:46 +0000 +Subject: [PATCH] overlays: Regularisation and improvements + +A few small improvements, with a view to making the updated overlays +behave the same before and after the big conversion. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/ads1115-overlay.dts | 3 ++- + arch/arm/boot/dts/overlays/i2c-fan-overlay.dts | 4 ++-- + arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 3 ++- + arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts | 3 ++- + arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 3 ++- + arch/arm/boot/dts/overlays/pca953x-overlay.dts | 2 -- + arch/arm/boot/dts/overlays/pcf857x-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +- + 9 files changed, 13 insertions(+), 11 deletions(-) + +--- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts +@@ -120,7 +120,8 @@ + chd_cfg = <&channel_d>,"reg:0"; + chd_gain = <&channel_d>,"ti,gain:0"; + chd_datarate = <&channel_d>,"ti,datarate:0"; +- i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; + i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +--- a/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts +@@ -17,7 +17,6 @@ + emc2301: emc2301@2f { + compatible = "microchip,emc2301"; + reg = <0x2f>; +- status = "okay"; + #cooling-cells = <0x02>; + }; + }; +@@ -82,7 +81,8 @@ + }; + + __overrides__ { +- i2c0 = <&frag100>,"target:0=",<&i2c0>; ++ i2c0 = <&frag100>,"target:0=",<&i2c0>, ++ <0>,"+101+102"; + i2c_csi_dsi = <&frag100>,"target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; + i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts +@@ -27,7 +27,8 @@ + }; + + __overrides__ { +- i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; + i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +@@ -27,7 +27,8 @@ + }; + + __overrides__ { +- i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; + i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -87,7 +87,8 @@ + addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0"; + mcp23008 = <0>,"=2"; + noints = <0>,"!1!3"; +- i2c0 = <&frag100>, "target:0=",<&i2c0>; ++ i2c0 = <&frag100>, "target:0=",<&i2c0>, ++ <0>,"+101+102"; + i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, + <0>,"+101+102"; + i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +--- a/arch/arm/boot/dts/overlays/pca953x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pca953x-overlay.dts +@@ -17,8 +17,6 @@ + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; +- +- status = "okay"; + }; + }; + }; +--- a/arch/arm/boot/dts/overlays/pcf857x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pcf857x-overlay.dts +@@ -11,13 +11,13 @@ + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; ++ status = "okay"; + + pcf857x: pcf857x@0 { + compatible = ""; + reg = <0x00>; + gpio-controller; + #gpio-cells = <2>; +- status = "okay"; + }; + }; + }; +--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts +@@ -27,7 +27,7 @@ + }; + + fragment@1 { +- target-path = "/"; ++ target = <&clocks>; + __overlay__ { + sc16is750_clk: sc16is750_i2c_clk@48 { + compatible = "fixed-clock"; +--- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts +@@ -27,7 +27,7 @@ + }; + + fragment@1 { +- target-path = "/"; ++ target = <&clocks>; + __overlay__ { + sc16is752_clk: sc16is752_i2c_clk@48 { + compatible = "fixed-clock"; diff --git a/target/linux/bcm27xx/patches-6.6/950-1527-overlays-Factor-out-the-common-i2c-bus-selection.patch b/target/linux/bcm27xx/patches-6.6/950-1527-overlays-Factor-out-the-common-i2c-bus-selection.patch new file mode 100644 index 00000000000..504e46376ad --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1527-overlays-Factor-out-the-common-i2c-bus-selection.patch @@ -0,0 +1,1630 @@ +From a320d39840745502d420f56b3d49b3723a12058f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sun, 26 Jan 2025 22:08:16 +0000 +Subject: [PATCH] overlays: Factor out the common i2c bus selection + +Create an i2c-buses.dtsi to hold all of the common I2C bus selection +logic, and refactor existing overlays to use it. This patch should +have no functional change overall except to increase the range of +options for some overlays. + +There is a slightly ugly mechanism for overriding the default bus, where +the mux nodes may or may not need to be enabled. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 264 ++++------------- + .../arm/boot/dts/overlays/ads1115-overlay.dts | 39 +-- + .../boot/dts/overlays/edt-ft5406-overlay.dts | 39 +-- + arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 5 +- + arch/arm/boot/dts/overlays/i2c-buses.dtsi | 67 +++++ + .../arm/boot/dts/overlays/i2c-fan-overlay.dts | 45 +-- + .../arm/boot/dts/overlays/i2c-mux-overlay.dts | 42 +-- + .../dts/overlays/i2c-pwm-pca9685a-overlay.dts | 41 +-- + .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 43 +-- + .../boot/dts/overlays/i2c-sensor-overlay.dts | 43 +-- + .../boot/dts/overlays/mcp23017-overlay.dts | 47 +-- + .../arm/boot/dts/overlays/pca953x-overlay.dts | 277 +++--------------- + .../arm/boot/dts/overlays/pcf857x-overlay.dts | 38 +-- + .../dts/overlays/sc16is750-i2c-overlay.dts | 37 +-- + .../dts/overlays/sc16is752-i2c-overlay.dts | 37 +-- + .../overlays/seeed-can-fd-hat-v2-overlay.dts | 9 +- + .../overlays/vc4-kms-dsi-7inch-overlay.dts | 17 +- + .../vc4-kms-dsi-waveshare-800x480-overlay.dts | 15 +- + 18 files changed, 202 insertions(+), 903 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/i2c-buses.dtsi + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -568,6 +568,8 @@ Load: dtoverlay=ads1115,[= + Params: addr I2C bus address of device. Set based on how the + addr pin is wired. (default=0x48 assumes addr + is pulled to GND) ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + cha_enable Enable virtual channel a. + cha_cfg Set the configuration for virtual channel a. + (default=4 configures this channel for the +@@ -577,22 +579,6 @@ Params: addr I2C bus + cha_gain Set the gain of the Programmable Gain + Amplifier for this channel. (Default 1 sets the + full scale of the channel to 4.096 Volts) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C4 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c5 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + Channel parameters can be set for each enabled channel. + A maximum of 4 channels can be enabled (letters a thru d). +@@ -1263,20 +1249,11 @@ Params: sizex Touchscr + invx Touchscreen inverted x axis + invy Touchscreen inverted y axis + swapxy Touchscreen swapped x y axis +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c1 Choose the I2C1 bus on GPIOs 2&3 +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C4 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c5 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) + addr Sets the address for the touch controller. Note + that the device must be configured to use the + specified address. +- i2c-path Override I2C path to allow for i2c-gpio buses ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + + + Name: enc28j60 +@@ -2114,37 +2091,41 @@ Load: dtoverlay=i2c-bcm2708 + Params: + + +-Name: i2c-fan +-Info: Adds support for a number of I2C fan controllers +-Load: dtoverlay=i2c-fan,= +-Params: addr Sets the address for the fan controller. Note +- that the device must be configured to use the +- specified address. +- +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- ++Name: i2c-bus ++Info: This is not a real overlay. Many overlays support the use of a variety ++ of I2C buses, and this is where the relevant parameters are documented. ++Load: ++Params: i2c0 Choose the I2C0 bus on GPIOs 0&1 ++ i2c1 Choose the I2C1 bus on GPIOs 2&3 ++ i2c2 Choose the I2C2 bus (configure with the i2c2 ++ overlay - BCM2711 only) + i2c3 Choose the I2C3 bus (configure with the i2c3 + overlay - BCM2711 only) +- + i2c4 Choose the I2C4 bus (configure with the i2c4 + overlay - BCM2711 only) +- + i2c5 Choose the I2C5 bus (configure with the i2c5 + overlay - BCM2711 only) +- + i2c6 Choose the I2C6 bus (configure with the i2c6 + overlay - BCM2711 only) +- ++ i2c_csi_dsi Choose the I2C bus connected to the main ++ camera/display connector. ++ See "dtparam -h i2c_csi_dsi" for details. ++ i2c_csi_dsi0 Choose the I2C bus connected to the second ++ camera/display connector, if present. ++ See "dtparam -h i2c_csi_dsi0" for details. + i2c-path Override I2C path to allow for i2c-gpio buses + ++ ++Name: i2c-fan ++Info: Adds support for a number of I2C fan controllers ++Load: dtoverlay=i2c-fan,= ++Params: addr Sets the address for the fan controller. Note ++ that the device must be configured to use the ++ specified address. ++ ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" ++ + minpwm PWM setting for the fan when the SoC is below + mintemp (range 0-255. default 0) + maxpwm PWM setting for the fan when the SoC is above +@@ -2196,33 +2177,12 @@ Params: pca9542 Select t + + addr Change I2C address of the device (default 0x70) + ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" ++ + base Set an explicit base value for the channel bus + numbers + +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- +- i2c-path Override I2C path to allow for i2c-gpio buses +- + disconnect_on_idle Force the mux to disconnect all child buses + after every transaction. + +@@ -2234,22 +2194,8 @@ Name: i2c-pwm-pca9685a + Info: Adds support for an NXP PCA9685A I2C PWM controller on i2c_arm + Load: dtoverlay=i2c-pwm-pca9685a,= + Params: addr I2C address of PCA9685A (default 0x40) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + + + Name: i2c-rtc +@@ -2303,29 +2249,8 @@ Params: abx80x Select o + + s35390a Select the ABLIC S35390A device + +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- +- i2c-path Override I2C path to allow for i2c-gpio buses ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + + addr Sets the address for the RTC. Note that the + device must be configured to use the specified +@@ -2451,6 +2376,9 @@ Params: addr Set the + JC42, LM75, MCP980x, MPU6050, MPU9250, MS5637, + MS5803, MS5805, MS5837, MS8607, SHT3x or TMP102 + ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" ++ + adt7410 Select the Analog Devices ADT7410 and ADT7420 + temperature sensors + Valid address 0x48-0x4b, default 0x48 +@@ -2591,29 +2519,6 @@ Params: addr Set the + veml6070 Select the Vishay VEML6070 ultraviolet light + sensor + +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- +- i2c-path Override I2C path to allow for i2c-gpio buses +- + + Name: i2c0 + Info: Change i2c0 pin usage. Not all pin combinations are usable on all +@@ -3255,24 +3160,11 @@ Params: gpiopin Gpio pin + + addr I2C address of the MCP23017 (default: 0x20) + ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" ++ + mcp23008 Configure an MCP23008 instead. + noints Disable the interrupt GPIO line. +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C4 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c5 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + + Name: mcp23s17 +@@ -3692,6 +3584,8 @@ Name: pca953x + Info: TI PCA953x family of I2C GPIO expanders. Default is for NXP PCA9534. + Load: dtoverlay=pca953x,= + Params: addr I2C address of expander. Default 0x20. ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + pca6416 Select the NXP PCA6416 (16 bit) + pca9505 Select the NXP PCA9505 (40 bit) + pca9535 Select the NXP PCA9535 (16 bit) +@@ -3722,22 +3616,6 @@ Params: addr I2C addr + cat9554 Select the Onnn CAT9554 (8 bit) + pca9654 Select the Onnn PCA9654 (8 bit) + xra1202 Select the Exar XRA1202 (8 bit) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + + Name: pcf857x +@@ -3745,26 +3623,12 @@ Info: NXP PCF857x family of I2C GPIO e + Load: dtoverlay=pcf857x,= + Params: addr I2C address of expander. Default + depends on model selected. ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + pcf8574 Select the NXP PCF8574 (8 bit) + pcf8574a Select the NXP PCF8574A (8 bit) + pcf8575 Select the NXP PCF8575 (16 bit) + pca8574 Select the NXP PCA8574 (8 bit) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + + Name: pcie-32bit-dma +@@ -4463,23 +4327,9 @@ Info: Overlay for the NXP SC16IS750 UA + Load: dtoverlay=sc16is750-i2c,= + Params: int_pin GPIO used for IRQ (default 24) + addr Address (default 0x48) ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + xtal On-board crystal frequency (default 14745600) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C4 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c5 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + + Name: sc16is750-spi0 +@@ -4497,23 +4347,9 @@ Info: Overlay for the NXP SC16IS752 du + Load: dtoverlay=sc16is752-i2c,= + Params: int_pin GPIO used for IRQ (default 24) + addr Address (default 0x48) ++ i2c-bus Supports all the standard I2C bus selection ++ parameters - see "dtoverlay -h i2c-bus" + xtal On-board crystal frequency (default 14745600) +- i2c0 Choose the I2C0 bus on GPIOs 0&1 +- i2c_csi_dsi Choose the I2C bus connected to the main +- camera/display connector. +- See "dtparam -h i2c_csi_dsi" for details. +- i2c_csi_dsi0 Choose the I2C bus connected to the second +- camera/display connector, if present. +- See "dtparam -h i2c_csi_dsi0" for details. +- i2c3 Choose the I2C3 bus (configure with the i2c3 +- overlay - BCM2711 only) +- i2c4 Choose the I2C4 bus (configure with the i2c4 +- overlay - BCM2711 only) +- i2c5 Choose the I2C5 bus (configure with the i2c5 +- overlay - BCM2711 only) +- i2c6 Choose the I2C6 bus (configure with the i2c6 +- overlay - BCM2711 only) +- i2c-path Override I2C path to allow for i2c-gpio buses + + + Name: sc16is752-spi0 +--- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts +@@ -5,6 +5,8 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +@@ -81,27 +83,6 @@ + }; + }; + +- frag100: fragment@100 { +- target = <&i2c1>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + addr = <&ads1115>,"reg:0"; + cha_enable = <0>,"=0"; +@@ -120,21 +101,5 @@ + chd_cfg = <&channel_d>,"reg:0"; + chd_gain = <&channel_d>,"ti,gain:0"; + chd_datarate = <&channel_d>,"ti,datarate:0"; +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; + }; + }; +--- a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts ++++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts +@@ -7,43 +7,16 @@ + /dts-v1/; + /plugin/; + ++#define ENABLE_I2C0_MUX ++#include "i2c-buses.dtsi" + #include "edt-ft5406.dtsi" + +-/ { +- fragment@0 { +- target = <&i2c0if>; +- __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@1 { +- target = <&i2c0mux>; +- __overlay__ { +- status = "okay"; +- }; +- }; ++&busfrag { ++ target = <&i2c_csi_dsi>; ++}; + ++/ { + __overrides__ { +- i2c0 = <&ts_i2c_frag>,"target:0=",<&i2c0>; +- i2c1 = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path=i2c1", +- <0>,"-0-1"; +- i2c3 = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path=i2c3", +- <0>,"-0-1"; +- i2c4 = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path=i2c4", +- <0>,"-0-1"; +- i2c5 = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path=i2c5", +- <0>,"-0-1"; +- i2c6 = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path=i2c6", +- <0>,"-0-1"; +- i2c-path = <&ts_i2c_frag>, "target?=0", +- <&ts_i2c_frag>, "target-path", +- <0>,"-0-1"; + addr = <&ft5406>,"reg:0"; + }; + }; +--- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi ++++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +@@ -22,12 +22,11 @@ + }; + }; + +- ts_i2c_frag: fragment@12 { +- target = <&i2c_csi_dsi>; ++ fragment@12 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + ft5406: ts@38 { + compatible = "edt,edt-ft5506"; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/i2c-buses.dtsi +@@ -0,0 +1,67 @@ ++// Common i2c buses, and dtparams to select them ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ busfrag: fragment@100 { ++ target = <&i2c_arm>; ++ i2cbus: __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@101 { ++ target = <&i2c0if>; ++#ifdef ENABLE_I2C0_MUX ++ __overlay__ { ++#else ++ __dormant__ { ++#endif ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@102 { ++ target = <&i2c0mux>; ++#ifdef ENABLE_I2C0_MUX ++ __overlay__ { ++#else ++ __dormant__ { ++#endif ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ i2c0 = <&busfrag>,"target:0=",<&i2c0>, ++ <&busfrag>, "target-path?=0", ++ <0>,"+101+102"; ++ i2c_csi_dsi = <&busfrag>,"target:0=",<&i2c_csi_dsi>, ++ <&busfrag>, "target-path?=0", ++ <0>,"+101+102"; ++ i2c_csi_dsi0 = <&busfrag>, "target:0=",<&i2c_csi_dsi0>, ++ <&busfrag>, "target-path?=0", ++ <0>,"+101+102"; ++ i2c1 = <&busfrag>,"target:0=",<&i2c1>, ++ <&busfrag>, "target-path?=0", ++ <0>,"-101-102"; ++ i2c2 = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path=i2c2", ++ <0>,"-101-102"; ++ i2c3 = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path=i2c3", ++ <0>,"-101-102"; ++ i2c4 = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path=i2c4", ++ <0>,"-101-102"; ++ i2c5 = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path=i2c5", ++ <0>,"-101-102"; ++ i2c6 = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path=i2c6", ++ <0>,"-101-102"; ++ i2c-path = <&busfrag>, "target?=0", ++ <&busfrag>, "target-path", ++ <0>,"-101-102"; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts +@@ -4,6 +4,8 @@ + + #include + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +@@ -22,35 +24,14 @@ + }; + }; + +- frag100: fragment@100 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@103 { ++ fragment@1 { + target = <&cpu_thermal>; + __overlay__ { + polling-delay = <2000>; /* milliseconds */ + }; + }; + +- fragment@104 { ++ fragment@2 { + target = <&thermal_trips>; + __overlay__ { + fanmid0: fanmid0 { +@@ -66,7 +47,7 @@ + }; + }; + +- fragment@105 { ++ fragment@3 { + target = <&cooling_maps>; + __overlay__ { + map0: map0 { +@@ -81,22 +62,6 @@ + }; + + __overrides__ { +- i2c0 = <&frag100>,"target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>,"target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; + addr = <&emc2301>,"reg:0"; + minpwm = <&emc2301>,"emc2305,pwm-min.0"; + maxpwm = <&emc2301>,"emc2305,pwm-max.0"; +--- a/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts +@@ -5,6 +5,8 @@ + + #include + ++#include "i2c-buses.dtsi" ++ + /{ + compatible = "brcm,bcm2835"; + +@@ -13,7 +15,6 @@ + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + pca9542: mux@70 { + compatible = "nxp,pca9542"; +@@ -40,7 +41,6 @@ + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + pca9545: mux@70 { + compatible = "nxp,pca9545"; +@@ -77,7 +77,6 @@ + __dormant__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + pca9548: mux@70 { + compatible = "nxp,pca9548"; +@@ -129,27 +128,6 @@ + }; + }; + +- frag100: fragment@100 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + pca9542 = <0>, "+0"; + pca9545 = <0>, "+1"; +@@ -163,22 +141,6 @@ + <&pca9545>,"base-nr:0", + <&pca9548>,"base-nr:0"; + +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; + disconnect_on_idle = + <&pca9542>,"idle-state:0=", , + <&pca9545>,"idle-state:0=", , +--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts +@@ -2,6 +2,8 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + /{ + compatible = "brcm,bcm2835"; + +@@ -10,7 +12,6 @@ + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + pca: pca@40 { + compatible = "nxp,pca9685-pwm"; +@@ -21,45 +22,7 @@ + }; + }; + +- +- frag100: fragment@100 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + addr = <&pca>,"reg:0"; +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; + }; + }; +--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts +@@ -3,45 +3,4 @@ + /plugin/; + + #include "i2c-rtc-common.dtsi" +- +-/ { +- frag100: fragment@100 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- __overrides__ { +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; +- }; +-}; ++#include "i2c-buses.dtsi" +--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +@@ -3,45 +3,4 @@ + /plugin/; + + #include "i2c-sensor-common.dtsi" +- +-/ { +- frag100: fragment@100 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- __overrides__ { +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; +- }; +-}; ++#include "i2c-buses.dtsi" +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -3,16 +3,11 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +- fragment@0 { +- target = <&i2cbus>; +- __overlay__ { +- status = "okay"; +- }; +- }; +- + fragment@1 { + target = <&gpio>; + __overlay__ { +@@ -60,49 +55,11 @@ + }; + }; + +- frag100: fragment@100 { +- target = <&i2c1>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@102 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + gpiopin = <&mcp23017_pins>,"brcm,pins:0", + <&mcp23017_irq>,"interrupts:0"; + addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0"; + mcp23008 = <0>,"=2"; + noints = <0>,"!1!3"; +- i2c0 = <&frag100>, "target:0=",<&i2c0>, +- <0>,"+101+102"; +- i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+101+102"; +- i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+101+102"; +- i2c3 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c3"; +- i2c4 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c4"; +- i2c5 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c5"; +- i2c6 = <&frag100>, "target?=0", +- <&frag100>, "target-path=i2c6"; +- i2c-path = <&frag100>, "target?=0", +- <&frag100>, "target-path"; + }; + }; +- +--- a/arch/arm/boot/dts/overlays/pca953x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pca953x-overlay.dts +@@ -2,11 +2,13 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + /{ + compatible = "brcm,bcm2835"; + +- frag0: fragment@0 { +- target = <&i2c_arm>; ++ fragment@0 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +@@ -21,248 +23,37 @@ + }; + }; + +- fragment@1 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca6416"; +- }; +- }; +- fragment@2 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9505"; +- }; +- }; +- fragment@3 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9535"; +- }; +- }; +- fragment@4 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9536"; +- }; +- }; +- fragment@5 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9537"; +- }; +- }; +- fragment@6 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9538"; +- }; +- }; +- fragment@7 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9539"; +- }; +- }; +- fragment@8 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9554"; +- }; +- }; +- fragment@9 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9555"; +- }; +- }; +- fragment@10 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9556"; +- }; +- }; +- fragment@11 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9557"; +- }; +- }; +- fragment@12 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9574"; +- }; +- }; +- fragment@13 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9575"; +- }; +- }; +- fragment@14 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pca9698"; +- }; +- }; +- fragment@15 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pcal6416"; +- }; +- }; +- fragment@16 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pcal6524"; +- }; +- }; +- fragment@17 { +- target = <&pca>; +- __dormant__ { +- compatible = "nxp,pcal9555a"; +- }; +- }; +- fragment@18 { +- target = <&pca>; +- __dormant__ { +- compatible = "maxim,max7310"; +- }; +- }; +- fragment@19 { +- target = <&pca>; +- __dormant__ { +- compatible = "maxim,max7312"; +- }; +- }; +- fragment@20 { +- target = <&pca>; +- __dormant__ { +- compatible = "maxim,max7313"; +- }; +- }; +- fragment@21 { +- target = <&pca>; +- __dormant__ { +- compatible = "maxim,max7315"; +- }; +- }; +- fragment@22 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,pca6107"; +- }; +- }; +- fragment@23 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,tca6408"; +- }; +- }; +- fragment@24 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,tca6416"; +- }; +- }; +- fragment@25 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,tca6424"; +- }; +- }; +- fragment@26 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,tca9539"; +- }; +- }; +- fragment@27 { +- target = <&pca>; +- __dormant__ { +- compatible = "ti,tca9554"; +- }; +- }; +- fragment@28 { +- target = <&pca>; +- __dormant__ { +- compatible = "onnn,cat9554"; +- }; +- }; +- fragment@29 { +- target = <&pca>; +- __dormant__ { +- compatible = "onnn,pca9654"; +- }; +- }; +- fragment@30 { +- target = <&pca>; +- __dormant__ { +- compatible = "exar,xra1202"; +- }; +- }; +- +- fragment@100 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + addr = <&pca>,"reg:0"; +- pca6416 = <0>, "+1"; +- pca9505 = <0>, "+2"; +- pca9535 = <0>, "+3"; +- pca9536 = <0>, "+4"; +- pca9537 = <0>, "+5"; +- pca9538 = <0>, "+6"; +- pca9539 = <0>, "+7"; +- pca9554 = <0>, "+8"; +- pca9555 = <0>, "+9"; +- pca9556 = <0>, "+10"; +- pca9557 = <0>, "+11"; +- pca9574 = <0>, "+12"; +- pca9575 = <0>, "+13"; +- pca9698 = <0>, "+14"; +- pcal6416 = <0>, "+15"; +- pcal6524 = <0>, "+16"; +- pcal9555a = <0>, "+17"; +- max7310 = <0>, "+18"; +- max7312 = <0>, "+19"; +- max7313 = <0>, "+20"; +- max7315 = <0>, "+21"; +- pca6107 = <0>, "+22"; +- tca6408 = <0>, "+23"; +- tca6416 = <0>, "+24"; +- tca6424 = <0>, "+25"; +- tca9539 = <0>, "+26"; +- tca9554 = <0>, "+27"; +- cat9554 = <0>, "+28"; +- pca9654 = <0>, "+29"; +- xra1202 = <0>, "+30"; +- i2c0 = <&frag0>, "target:0=",<&i2c0>, +- <0>,"+100+101"; +- i2c_csi_dsi = <&frag0>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+100+101"; +- i2c_csi_dsi0 = <&frag0>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+100+101"; +- i2c3 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c3"; +- i2c4 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c4"; +- i2c5 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c5"; +- i2c6 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c6"; +- i2c-path = <&frag0>, "target?=0", +- <&frag0>, "target-path"; ++ pca6416 = <&pca>,"compatible=nxp,pca6416"; ++ pca9505 = <&pca>,"compatible=nxp,pca9505"; ++ pca9535 = <&pca>,"compatible=nxp,pca9535"; ++ pca9536 = <&pca>,"compatible=nxp,pca9536"; ++ pca9537 = <&pca>,"compatible=nxp,pca9537"; ++ pca9538 = <&pca>,"compatible=nxp,pca9538"; ++ pca9539 = <&pca>,"compatible=nxp,pca9539"; ++ pca9554 = <&pca>,"compatible=nxp,pca9554"; ++ pca9555 = <&pca>,"compatible=nxp,pca9555"; ++ pca9556 = <&pca>,"compatible=nxp,pca9556"; ++ pca9557 = <&pca>,"compatible=nxp,pca9557"; ++ pca9574 = <&pca>,"compatible=nxp,pca9574"; ++ pca9575 = <&pca>,"compatible=nxp,pca9575"; ++ pca9698 = <&pca>,"compatible=nxp,pca9698"; ++ pcal6416 = <&pca>,"compatible=nxp,pcal6416"; ++ pcal6524 = <&pca>,"compatible=nxp,pcal6524"; ++ pcal9555a = <&pca>,"compatible=nxp,pcal9555a"; ++ max7310 = <&pca>,"compatible=maxim,max7310"; ++ max7312 = <&pca>,"compatible=maxim,max7312"; ++ max7313 = <&pca>,"compatible=maxim,max7313"; ++ max7315 = <&pca>,"compatible=maxim,max7315"; ++ pca6107 = <&pca>,"compatible=ti,pca6107"; ++ tca6408 = <&pca>,"compatible=ti,tca6408"; ++ tca6416 = <&pca>,"compatible=ti,tca6416"; ++ tca6424 = <&pca>,"compatible=ti,tca6424"; ++ tca9539 = <&pca>,"compatible=ti,tca9539"; ++ tca9554 = <&pca>,"compatible=ti,tca9554"; ++ cat9554 = <&pca>,"compatible=onnn,cat9554"; ++ pca9654 = <&pca>,"compatible=onnn,pca9654"; ++ xra1202 = <&pca>,"compatible=exar,xra1202"; + }; + }; +--- a/arch/arm/boot/dts/overlays/pcf857x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pcf857x-overlay.dts +@@ -3,11 +3,13 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +- frag0: fragment@0 { +- target = <&i2c_arm>; ++ fragment@0 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +@@ -22,41 +24,11 @@ + }; + }; + +- fragment@100 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + pcf8574 = <&pcf857x>,"compatible=nxp,pcf8574", <&pcf857x>,"reg:0=0x20"; + pcf8574a = <&pcf857x>,"compatible=nxp,pcf8574a", <&pcf857x>,"reg:0=0x38"; + pcf8575 = <&pcf857x>,"compatible=nxp,pcf8575", <&pcf857x>,"reg:0=0x20"; +- pca8574 = <&pcf857x>,"compatible=nxp,pca8574", <&pcf857x>,"reg:0=0x20"; ++ pca8574 = <&pcf857x>,"compatible=nxp,pca8574", <&pcf857x>,"reg:0=0x20"; + addr = <&pcf857x>,"reg:0"; +- i2c0 = <&frag0>, "target:0=",<&i2c0>, +- <0>,"+100+101"; +- i2c_csi_dsi = <&frag0>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+100+101"; +- i2c_csi_dsi0 = <&frag0>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+100+101"; +- i2c3 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c3"; +- i2c4 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c4"; +- i2c5 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c5"; +- i2c6 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c6"; +- i2c-path = <&frag0>, "target?=0", +- <&frag0>, "target-path"; + }; + }; +--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts +@@ -1,15 +1,16 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +- frag0: fragment@0 { +- target = <&i2c_arm>; ++ fragment@0 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + sc16is750: sc16is750@48 { + compatible = "nxp,sc16is750"; +@@ -48,40 +49,10 @@ + }; + }; + +- fragment@100 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + int_pin = <&sc16is750>,"interrupts:0", <&int_pins>,"brcm,pins:0", + <&int_pins>,"reg:0"; + addr = <&sc16is750>,"reg:0", <&sc16is750_clk>,"name"; + xtal = <&sc16is750_clk>,"clock-frequency:0"; +- i2c0 = <&frag0>, "target:0=",<&i2c0>, +- <0>,"+100+101"; +- i2c_csi_dsi = <&frag0>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+100+101"; +- i2c_csi_dsi0 = <&frag0>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+100+101"; +- i2c3 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c3"; +- i2c4 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c4"; +- i2c5 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c5"; +- i2c6 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c6"; +- i2c-path = <&frag0>, "target?=0", +- <&frag0>, "target-path"; + }; + }; +--- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts +@@ -1,15 +1,16 @@ + /dts-v1/; + /plugin/; + ++#include "i2c-buses.dtsi" ++ + / { + compatible = "brcm,bcm2835"; + +- frag0: fragment@0 { +- target = <&i2c_arm>; ++ fragment@0 { ++ target = <&i2cbus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; +- status = "okay"; + + sc16is752: sc16is752@48 { + compatible = "nxp,sc16is752"; +@@ -48,40 +49,10 @@ + }; + }; + +- fragment@100 { +- target = <&i2c0if>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- +- fragment@101 { +- target = <&i2c0mux>; +- __dormant__ { +- status = "okay"; +- }; +- }; +- + __overrides__ { + int_pin = <&sc16is752>,"interrupts:0", <&int_pins>,"brcm,pins:0", + <&int_pins>,"reg:0"; + addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name"; + xtal = <&sc16is752_clk>,"clock-frequency:0"; +- i2c0 = <&frag0>, "target:0=",<&i2c0>, +- <0>,"+100+101"; +- i2c_csi_dsi = <&frag0>, "target:0=",<&i2c_csi_dsi>, +- <0>,"+100+101"; +- i2c_csi_dsi0 = <&frag0>, "target:0=",<&i2c_csi_dsi0>, +- <0>,"+100+101"; +- i2c3 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c3"; +- i2c4 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c4"; +- i2c5 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c5"; +- i2c6 = <&frag0>, "target?=0", +- <&frag0>, "target-path=i2c6"; +- i2c-path = <&frag0>, "target?=0", +- <&frag0>, "target-path"; + }; + }; +--- a/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts ++++ b/arch/arm/boot/dts/overlays/seeed-can-fd-hat-v2-overlay.dts +@@ -98,8 +98,9 @@ + }; + }; + fragment@8 { +- target = <&i2cbus>; ++ target = <&i2c_arm>; + __overlay__ { ++ status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pcf85063@51 { +@@ -108,10 +109,4 @@ + }; + }; + }; +- fragment@9 { +- target = <&i2c_arm>; +- i2cbus: __overlay__ { +- status = "okay"; +- }; +- }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +@@ -1,4 +1,4 @@ +-/* ++ /* + * Device Tree overlay for RaspberryPi 7" Touchscreen panel + * + */ +@@ -8,6 +8,11 @@ + + #include "edt-ft5406.dtsi" + ++&ft5406 { ++ vcc-supply = <®_display>; ++ reset-gpio = <®_display 1 1>; ++}; ++ + / { + /* No compatible as it will have come from edt-ft5406.dtsi */ + +@@ -77,7 +82,7 @@ + + i2c_frag: fragment@2 { + target = <&i2c_csi_dsi>; +- __overlay__ { ++ i2cbus: __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +@@ -104,18 +109,10 @@ + status = "okay"; + }; + }; +- fragment@5 { +- target = <&ft5406>; +- __overlay__ { +- vcc-supply = <®_display>; +- reset-gpio = <®_display 1 1>; +- }; +- }; + + __overrides__ { + dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, + <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, +- <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <&panel_disp>, "reg:0=0", + <®_bridge>, "reg:0=0", + <®_bridge>, "regulator-name=bridge_reg_0"; +--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-800x480-overlay.dts +@@ -9,6 +9,11 @@ + + #include "edt-ft5406.dtsi" + ++&ft5406 { ++ vcc-supply = <®_display>; ++ reset-gpio = <®_display 1 1>; ++}; ++ + / { + /* No compatible as it will have come from edt-ft5406.dtsi */ + +@@ -73,7 +78,7 @@ + + i2c_frag: fragment@2 { + target = <&i2c_csi_dsi>; +- __overlay__ { ++ i2cbus: __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +@@ -100,18 +105,10 @@ + status = "okay"; + }; + }; +- fragment@5 { +- target = <&ft5406>; +- __overlay__ { +- vcc-supply = <®_display>; +- reset-gpio = <®_display 1 1>; +- }; +- }; + + __overrides__ { + dsi0 = <&dsi_frag>, "target:0=",<&dsi0>, + <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, +- <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>, + <®_bridge>, "reg:0=0", + <®_bridge>, "regulator-name=bridge_reg_0"; + disable_touch = <&ft5406>, "status=disabled"; diff --git a/target/linux/bcm27xx/patches-6.6/950-1529-misc-rp1-pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch b/target/linux/bcm27xx/patches-6.6/950-1529-misc-rp1-pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch new file mode 100644 index 00000000000..a084ec698b0 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1529-misc-rp1-pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch @@ -0,0 +1,63 @@ +From 8a08b4ad6dbd48a826b3052e52a4fdc88c3ac36e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 30 Jan 2025 15:26:39 +0000 +Subject: [PATCH] misc: rp1-pio: SM_CONFIG_XFER32 = larger DMA bufs + +Add an ioctl type - SM_CONFIG_XFER32 - that takes uints for the buf_size +and buf_count values. + +Signed-off-by: Phil Elwell +--- + drivers/misc/rp1-pio.c | 9 +++++++++ + include/uapi/misc/rp1_pio_if.h | 8 ++++++++ + 2 files changed, 17 insertions(+) + +--- a/drivers/misc/rp1-pio.c ++++ b/drivers/misc/rp1-pio.c +@@ -710,6 +710,14 @@ static int rp1_pio_sm_config_xfer_user(s + args->buf_size, args->buf_count); + } + ++static int rp1_pio_sm_config_xfer32_user(struct rp1_pio_client *client, void *param) ++{ ++ struct rp1_pio_sm_config_xfer32_args *args = param; ++ ++ return rp1_pio_sm_config_xfer_internal(client, args->sm, args->dir, ++ args->buf_size, args->buf_count); ++} ++ + static int rp1_pio_sm_tx_user(struct rp1_pio_device *pio, struct dma_info *dma, + const void __user *userbuf, size_t bytes) + { +@@ -970,6 +978,7 @@ struct handler_info { + HANDLER(SM_CONFIG_XFER, sm_config_xfer_user), + HANDLER(SM_XFER_DATA, sm_xfer_data_user), + HANDLER(SM_XFER_DATA32, sm_xfer_data32_user), ++ HANDLER(SM_CONFIG_XFER32, sm_config_xfer32_user), + + HANDLER(CAN_ADD_PROGRAM, can_add_program), + HANDLER(ADD_PROGRAM, add_program), +--- a/include/uapi/misc/rp1_pio_if.h ++++ b/include/uapi/misc/rp1_pio_if.h +@@ -160,6 +160,13 @@ struct rp1_pio_sm_config_xfer_args { + uint16_t buf_count; + }; + ++struct rp1_pio_sm_config_xfer32_args { ++ uint16_t sm; ++ uint16_t dir; ++ uint32_t buf_size; ++ uint32_t buf_count; ++}; ++ + struct rp1_pio_sm_xfer_data_args { + uint16_t sm; + uint16_t dir; +@@ -185,6 +192,7 @@ struct rp1_access_hw_args { + #define PIO_IOC_SM_CONFIG_XFER _IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args) + #define PIO_IOC_SM_XFER_DATA _IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args) + #define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args) ++#define PIO_IOC_SM_CONFIG_XFER32 _IOW(PIO_IOC_MAGIC, 3, struct rp1_pio_sm_config_xfer32_args) + + #define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args) + #define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args) diff --git a/target/linux/bcm27xx/patches-6.6/950-1530-spi-dw-Wait-for-idle-after-TX.patch b/target/linux/bcm27xx/patches-6.6/950-1530-spi-dw-Wait-for-idle-after-TX.patch new file mode 100644 index 00000000000..fa32b711960 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1530-spi-dw-Wait-for-idle-after-TX.patch @@ -0,0 +1,29 @@ +From 54a442deb925c37346abbbcc566234757925910c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2025 17:50:20 +0000 +Subject: [PATCH] spi: dw: Wait for idle after TX + +If this is a DMA transfer, and if there is no simultaneous RX transfer, +wait for the interface to go idle before reporting that TX is done. + +Link: https://forums.raspberrypi.com/viewtopic.php?t=383027 + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-dw-dma.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/spi/spi-dw-dma.c ++++ b/drivers/spi/spi-dw-dma.c +@@ -304,6 +304,11 @@ static int dw_spi_dma_wait_tx_done(struc + return -EIO; + } + ++ if (!xfer->rx_buf) { ++ while (dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY) ++ cpu_relax(); ++ } ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1531-misc-rp1-pio-Error-out-on-incompatible-firmware.patch b/target/linux/bcm27xx/patches-6.6/950-1531-misc-rp1-pio-Error-out-on-incompatible-firmware.patch new file mode 100644 index 00000000000..2fa70f38a1d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1531-misc-rp1-pio-Error-out-on-incompatible-firmware.patch @@ -0,0 +1,42 @@ +From e0a21a407b78477aa530800255d53405950cb1fb Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2025 14:44:08 +0000 +Subject: [PATCH] misc: rp1-pio: Error out on incompatible firmware + +If the RP1 firmware has reported an error then return that from the PIO +probe function, otherwise defer the probing. + +Link: https://github.com/raspberrypi/linux/issues/6642 + +Signed-off-by: Phil Elwell +--- + drivers/misc/rp1-pio.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/misc/rp1-pio.c ++++ b/drivers/misc/rp1-pio.c +@@ -1277,8 +1277,10 @@ static int rp1_pio_probe(struct platform + return dev_err_probe(dev, pdev->id, "alias is missing\n"); + + fw = devm_rp1_firmware_get(dev, dev->of_node); +- if (IS_ERR_OR_NULL(fw)) +- return dev_err_probe(dev, -ENOENT, "failed to contact RP1 firmware\n"); ++ if (!fw) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find RP1 firmware driver\n"); ++ if (IS_ERR(fw)) ++ return dev_err_probe(dev, PTR_ERR(fw), "failed to contact RP1 firmware\n"); + ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count); + if (ret < 0) + return ret; +@@ -1355,6 +1357,11 @@ static void rp1_pio_remove(struct platfo + + if (g_pio == pio) + g_pio = NULL; ++ ++ device_destroy(pio->dev_class, pio->dev_num); ++ cdev_del(&pio->cdev); ++ class_destroy(pio->dev_class); ++ unregister_chrdev_region(pio->dev_num, 1); + } + + static const struct of_device_id rp1_pio_ids[] = { diff --git a/target/linux/bcm27xx/patches-6.6/950-1532-firmware-rp1-Linger-on-firmware-failure.patch b/target/linux/bcm27xx/patches-6.6/950-1532-firmware-rp1-Linger-on-firmware-failure.patch new file mode 100644 index 00000000000..cf0bbc8c49c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1532-firmware-rp1-Linger-on-firmware-failure.patch @@ -0,0 +1,103 @@ +From 3f60adc5ce8238996ec43d2b76a6e38e46f8271b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2025 14:51:52 +0000 +Subject: [PATCH] firmware: rp1: Linger on firmware failure + +To avoid pointless retries, let the probe function succeed if the +firmware interface is configured correctly but the firmware is +incompatible. The value of the private drvdata field holds the outcome. + +Link: https://github.com/raspberrypi/linux/issues/6642 + +Signed-off-by: Phil Elwell +--- + drivers/firmware/rp1.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/firmware/rp1.c ++++ b/drivers/firmware/rp1.c +@@ -114,7 +114,8 @@ static void rp1_firmware_delete(struct k + + void rp1_firmware_put(struct rp1_firmware *fw) + { +- kref_put(&fw->consumers, rp1_firmware_delete); ++ if (!IS_ERR_OR_NULL(fw)) ++ kref_put(&fw->consumers, rp1_firmware_delete); + } + EXPORT_SYMBOL_GPL(rp1_firmware_put); + +@@ -157,7 +158,7 @@ struct rp1_firmware *rp1_firmware_get(st + const char *match = rp1_firmware_of_match[0].compatible; + struct platform_device *pdev; + struct device_node *fwnode; +- struct rp1_firmware *fw; ++ struct rp1_firmware *fw = NULL; + + if (!client) + return NULL; +@@ -166,17 +167,17 @@ struct rp1_firmware *rp1_firmware_get(st + return NULL; + if (!of_device_is_compatible(fwnode, match)) { + of_node_put(fwnode); +- return NULL; ++ return ERR_PTR(-ENXIO); + } + + pdev = of_find_device_by_node(fwnode); + of_node_put(fwnode); + + if (!pdev) +- goto err_exit; ++ return ERR_PTR(-ENXIO); + + fw = platform_get_drvdata(pdev); +- if (!fw) ++ if (IS_ERR_OR_NULL(fw)) + goto err_exit; + + if (!kref_get_unless_zero(&fw->consumers)) +@@ -188,7 +189,7 @@ struct rp1_firmware *rp1_firmware_get(st + + err_exit: + put_device(&pdev->dev); +- return NULL; ++ return fw; + } + EXPORT_SYMBOL_GPL(rp1_firmware_get); + +@@ -204,8 +205,8 @@ struct rp1_firmware *devm_rp1_firmware_g + int ret; + + fw = rp1_firmware_get(client); +- if (!fw) +- return NULL; ++ if (IS_ERR_OR_NULL(fw)) ++ return fw; + + ret = devm_add_action_or_reset(dev, devm_rp1_firmware_put, fw); + if (ret) +@@ -270,19 +271,18 @@ static int rp1_firmware_probe(struct pla + init_completion(&fw->c); + kref_init(&fw->consumers); + +- platform_set_drvdata(pdev, fw); +- + ret = rp1_firmware_message(fw, GET_FIRMWARE_VERSION, + NULL, 0, &version, sizeof(version)); + if (ret == sizeof(version)) { + dev_info(dev, "RP1 Firmware version %08x%08x%08x%08x%08x\n", + version[0], version[1], version[2], version[3], version[4]); +- ret = 0; +- } else if (ret >= 0) { +- ret = -EIO; ++ platform_set_drvdata(pdev, fw); ++ } else { ++ rp1_firmware_put(fw); ++ platform_set_drvdata(pdev, ERR_PTR(-ENOENT)); + } + +- return ret; ++ return 0; + } + + static int rp1_firmware_remove(struct platform_device *pdev) diff --git a/target/linux/bcm27xx/patches-6.6/950-1533-mailbox-rp1-Don-t-claim-channels-in-of_xlate.patch b/target/linux/bcm27xx/patches-6.6/950-1533-mailbox-rp1-Don-t-claim-channels-in-of_xlate.patch new file mode 100644 index 00000000000..5d6014d68f2 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1533-mailbox-rp1-Don-t-claim-channels-in-of_xlate.patch @@ -0,0 +1,30 @@ +From 4d577c42b47dfffda80da995fafd5b16fdb242e2 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2025 13:18:45 +0000 +Subject: [PATCH] mailbox: rp1: Don't claim channels in of_xlate + +The of_xlate method saves the calculated event mask in the con_priv +field. It also rejects subsequent attempt to use that channel because +the mask is non-zero, which causes a repeated instantiation of a client +driver to fail. + +The of_xlate method is not meant to be a point of resource acquisition. +Leave the con_priv initialisation, but drop the test that it was +previously zero. + +Signed-off-by: Phil Elwell +--- + drivers/mailbox/rp1-mailbox.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/mailbox/rp1-mailbox.c ++++ b/drivers/mailbox/rp1-mailbox.c +@@ -133,8 +133,6 @@ static struct mbox_chan *rp1_mbox_xlate( + return ERR_PTR(-EINVAL); + + chan = &mbox->chans[doorbell]; +- if (chan->con_priv) +- return ERR_PTR(-EBUSY); + + chan->con_priv = (void *)(uintptr_t)(1 << doorbell); + diff --git a/target/linux/bcm27xx/patches-6.6/950-1534-fixup-spi-dw-Wait-for-idle-after-TX.patch b/target/linux/bcm27xx/patches-6.6/950-1534-fixup-spi-dw-Wait-for-idle-after-TX.patch new file mode 100644 index 00000000000..9ac62a3407d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1534-fixup-spi-dw-Wait-for-idle-after-TX.patch @@ -0,0 +1,25 @@ +From fab0093d88452972f05f4b13e91e31d00b55421a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2025 15:25:30 +0000 +Subject: [PATCH] fixup! spi: dw: Wait for idle after TX + +Relax a bit harder - transmission of the last bits may take a while. + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-dw-dma.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-dw-dma.c ++++ b/drivers/spi/spi-dw-dma.c +@@ -305,8 +305,9 @@ static int dw_spi_dma_wait_tx_done(struc + } + + if (!xfer->rx_buf) { ++ delay.value = dws->n_bytes * BITS_PER_BYTE; + while (dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY) +- cpu_relax(); ++ spi_delay_exec(&delay, xfer); + } + + return 0; diff --git a/target/linux/bcm27xx/patches-6.6/950-1535-dtoverlays-adds-support-for-Hifiberry-ADC8x-to-the-D.patch b/target/linux/bcm27xx/patches-6.6/950-1535-dtoverlays-adds-support-for-Hifiberry-ADC8x-to-the-D.patch new file mode 100644 index 00000000000..a742b30a345 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1535-dtoverlays-adds-support-for-Hifiberry-ADC8x-to-the-D.patch @@ -0,0 +1,76 @@ +From 2cdd83392ba025cc88072c0153d443fc59919960 Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Mon, 10 Feb 2025 14:58:34 +0100 +Subject: [PATCH] dtoverlays: adds support for Hifiberry ADC8x to the DAC8x + +Allows the usage of ADC8x stacked on top of the DAC8x. +Activates all I2S pins and uses now the dummy-dai instead +of the formerly used pcm5102 to allow the use of a +capture device, too. The simple card driver will +probe for the ADC8x and may activate the 8 channel +capture. Uses GPIO5 for detection. + +Signed-off-by: j-schambacher +--- + arch/arm/boot/dts/overlays/README | 3 +++ + .../boot/dts/overlays/hifiberry-dac8x-overlay.dts | 14 ++++++++++---- + 2 files changed, 13 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1879,6 +1879,9 @@ Params: + + Name: hifiberry-dac8x + Info: Configures the HifiBerry DAC8X audio cards (only on Pi5) ++ This driver also detects a stacked ADC8x and activates the ++ capture capabilities. ++ Note: for standalone use of the ADC8x activate the ADC8x module. + Load: dtoverlay=hifiberry-dac8x + Params: + +--- a/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts +@@ -1,7 +1,10 @@ ++// SPDX-License-Identifier: GPL-2.0 + // Definitions for HiFiBerry DAC8x + /dts-v1/; + /plugin/; + ++#include ++ + / { + compatible = "brcm,bcm2712"; + +@@ -10,8 +13,10 @@ + __overlay__ { + rp1_i2s0_dac8x: rp1_i2s0_dac8x { + function = "i2s0"; +- pins = "gpio18", "gpio19", "gpio21", +- "gpio23", "gpio25", "gpio27"; ++ pins = "gpio18", "gpio19", "gpio20", ++ "gpio21", "gpio22", "gpio23", ++ "gpio24", "gpio25", "gpio26", ++ "gpio27"; + bias-disable; + status = "okay"; + }; +@@ -30,9 +35,9 @@ + fragment@2 { + target-path = "/"; + __overlay__ { +- pcm5102a-codec { ++ dummy-codec { + #sound-dai-cells = <0>; +- compatible = "ti,pcm5102a"; ++ compatible = "snd-soc-dummy"; + status = "okay"; + }; + }; +@@ -43,6 +48,7 @@ + __overlay__ { + compatible = "hifiberry,hifiberry-dac8x"; + i2s-controller = <&i2s_clk_producer>; ++ hasadc-gpio = <&gpio 5 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + }; diff --git a/target/linux/bcm27xx/patches-6.6/950-1536-ASoC-adds-ADC8x-support-to-the-Hifiberry-DAC8x.patch b/target/linux/bcm27xx/patches-6.6/950-1536-ASoC-adds-ADC8x-support-to-the-Hifiberry-DAC8x.patch new file mode 100644 index 00000000000..fec52cc60f1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1536-ASoC-adds-ADC8x-support-to-the-Hifiberry-DAC8x.patch @@ -0,0 +1,75 @@ +From d664f45f77423b03e5a435e480822075c03331bd Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Mon, 10 Feb 2025 15:08:48 +0100 +Subject: [PATCH] ASoC: adds ADC8x support to the Hifiberry DAC8x + +The driver probes for the ADC8x which can be stacked on top +of the DAC8x. It enables a symmetric 8 channel capture using +the dummy-dai. + +Signed-off-by: j-schambacher +--- + sound/soc/bcm/rpi-simple-soundcard.c | 38 +++++++++++++++++++++++++--- + 1 file changed, 34 insertions(+), 4 deletions(-) + +--- a/sound/soc/bcm/rpi-simple-soundcard.c ++++ b/sound/soc/bcm/rpi-simple-soundcard.c +@@ -354,16 +354,46 @@ static struct snd_rpi_simple_drvdata drv + .dai = snd_hifiberry_dac_dai, + }; + ++SND_SOC_DAILINK_DEFS(hifiberry_dac8x, ++ 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_dac8x_init(struct snd_soc_pcm_runtime *rtd) + { + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); ++ struct snd_soc_card *card = rtd->card; ++ struct gpio_desc *gpio_desc; ++ bool has_adc; + +- /* override the defaults to reflect 4 x PCM5102A on the card +- * and limit the sample rate to 192ksps +- */ ++ /* Configure the codec for 8 channel playback */ + codec_dai->driver->playback.channels_max = 8; + codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000; + ++ /* Activate capture based on ADC8x detection */ ++ gpio_desc = devm_gpiod_get(card->dev, "hasadc", GPIOD_IN); ++ if (IS_ERR(gpio_desc)) { ++ dev_err(card->dev, "Failed to get GPIO: %ld\n", PTR_ERR(gpio_desc)); ++ return PTR_ERR(gpio_desc); ++ } ++ ++ has_adc = gpiod_get_value(gpio_desc); ++ ++ if (has_adc) { ++ struct snd_soc_dai_link *dai = rtd->dai_link; ++ ++ dev_info(card->dev, "ADC8x detected: capture enabled\n"); ++ codec_dai->driver->symmetric_rate = 1; ++ codec_dai->driver->symmetric_channels = 1; ++ codec_dai->driver->symmetric_sample_bits = 1; ++ codec_dai->driver->capture.rates = SNDRV_PCM_RATE_8000_192000; ++ dai->name = "HiFiBerry DAC8xADC8x"; ++ dai->stream_name = "HiFiBerry DAC8xADC8x HiFi"; ++ } else { ++ dev_info(card->dev, "no ADC8x detected\n"); ++ rtd->dai_link->playback_only = 1; // Disable capture ++ } ++ + return 0; + } + +@@ -375,7 +405,7 @@ static struct snd_soc_dai_link snd_hifib + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .init = hifiberry_dac8x_init, +- SND_SOC_DAILINK_REG(hifiberry_dac), ++ SND_SOC_DAILINK_REG(hifiberry_dac8x), + }, + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch b/target/linux/bcm27xx/patches-6.6/950-1539-Reapply-usb-dwc3-Set-DMA-and-coherent-masks-early.patch similarity index 81% rename from target/linux/bcm27xx/patches-6.6/950-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch rename to target/linux/bcm27xx/patches-6.6/950-1539-Reapply-usb-dwc3-Set-DMA-and-coherent-masks-early.patch index a087faa35bc..327819f289f 100644 --- a/target/linux/bcm27xx/patches-6.6/950-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch +++ b/target/linux/bcm27xx/patches-6.6/950-1539-Reapply-usb-dwc3-Set-DMA-and-coherent-masks-early.patch @@ -1,50 +1,9 @@ -From fa846f5991de6c37db1f40e26a39f52c130f2bc7 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Mon, 13 Sep 2021 11:14:32 +0100 -Subject: [PATCH 0519/1085] usb: dwc3: Set DMA and coherent masks early +From 1b1e75ae7d69816609a95ff2fb92729a2ff04d8e Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Mon, 10 Feb 2025 13:26:33 +0000 +Subject: [PATCH] Reapply "usb: dwc3: Set DMA and coherent masks early" -dwc3 allocates scratch and event buffers in the top-level driver. Hack the -probe function to set the DMA mask before trying to allocate these. - -I think the event buffers are only used in device mode, but the scratch -buffers may be used if core hibernation is enabled. - -usb: dwc3: add support for new DT quirks - -Apply the optional axi-pipe-limit and dis-in-autoretry-quirk properties -during driver probe. - -Signed-off-by: Jonathan Bell - -phy: phy-brcm-usb: Add 2712 support - -usb: dwc3: if the host controller instance number is present in DT, use it - -If two instances of a dwc3 host controller are specified in devicetree, -then the probe order may be arbitrary which results in the device names -swapping on a per-boot basis. - -If a "usb" alias with the instance number is specified, then use -that to construct the device name instead of autogenerating one. - -Signed-off-by: Jonathan Bell - -rp1 dwc3 changes - -drivers: usb: dwc3: allow setting GTXTHRCFG on dwc_usb3.0 hardware - -Equivalent register fields exist in the SuperSpeed Host version of the -hardware, so allow the use of TX thresholds if specified in devicetree. - -Signed-off-by: Jonathan Bell - -drivers: usb: dwc3: remove downstream quirk dis-in-autoretry - -Upstream have unilaterally disabled the feature. - -Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream) - -Signed-off-by: Jonathan Bell +This reverts commit 09dfdf6129532e19b2cfd4992d1d09e7119ccd48. --- drivers/phy/broadcom/Kconfig | 2 +- .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++ @@ -246,7 +205,7 @@ Signed-off-by: Jonathan Bell ret = dwc3_phy_power_on(dwc); if (ret) goto err_exit_phy; -@@ -1377,6 +1397,24 @@ static int dwc3_core_init(struct dwc3 *d +@@ -1386,6 +1406,24 @@ static int dwc3_core_init(struct dwc3 *d dwc3_config_threshold(dwc); @@ -271,7 +230,7 @@ Signed-off-by: Jonathan Bell return 0; err_power_off_phy: -@@ -1520,6 +1558,7 @@ static void dwc3_get_properties(struct d +@@ -1529,6 +1567,7 @@ static void dwc3_get_properties(struct d u8 tx_thr_num_pkt_prd = 0; u8 tx_max_burst_prd = 0; u8 tx_fifo_resize_max_num; @@ -279,7 +238,7 @@ Signed-off-by: Jonathan Bell /* default to highest possible threshold */ lpm_nyet_threshold = 0xf; -@@ -1540,6 +1579,9 @@ static void dwc3_get_properties(struct d +@@ -1549,6 +1588,9 @@ static void dwc3_get_properties(struct d */ tx_fifo_resize_max_num = 6; @@ -289,7 +248,7 @@ Signed-off-by: Jonathan Bell dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = usb_get_dr_mode(dev); -@@ -1654,6 +1696,9 @@ static void dwc3_get_properties(struct d +@@ -1669,6 +1711,9 @@ static void dwc3_get_properties(struct d dwc->dis_split_quirk = device_property_read_bool(dev, "snps,dis-split-quirk"); @@ -299,7 +258,7 @@ Signed-off-by: Jonathan Bell dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; -@@ -1671,6 +1716,8 @@ static void dwc3_get_properties(struct d +@@ -1686,6 +1731,8 @@ static void dwc3_get_properties(struct d dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; dwc->tx_max_burst_prd = tx_max_burst_prd; @@ -308,7 +267,7 @@ Signed-off-by: Jonathan Bell dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; } -@@ -1963,6 +2010,12 @@ static int dwc3_probe(struct platform_de +@@ -1978,6 +2025,12 @@ static int dwc3_probe(struct platform_de if (IS_ERR(dwc->usb_psy)) return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n"); @@ -333,7 +292,7 @@ Signed-off-by: Jonathan Bell /* Global Debug LSP MUX Select */ #define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */ #define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff) -@@ -1067,6 +1070,7 @@ struct dwc3_scratchpad_array { +@@ -1070,6 +1073,7 @@ struct dwc3_scratchpad_array { * @tx_max_burst_prd: max periodic ESS transmit burst size * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @clear_stall_protocol: endpoint number that requires a delayed status phase @@ -341,7 +300,7 @@ Signed-off-by: Jonathan Bell * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise * @softconnect: true when gadget connect is called, false when disconnect runs -@@ -1304,6 +1308,7 @@ struct dwc3 { +@@ -1311,6 +1315,7 @@ struct dwc3 { u8 tx_max_burst_prd; u8 tx_fifo_resize_max_num; u8 clear_stall_protocol; diff --git a/target/linux/bcm27xx/patches-6.6/950-1541-overlays-Add-OpenHydroponics-RootMaster-overlay.patch b/target/linux/bcm27xx/patches-6.6/950-1541-overlays-Add-OpenHydroponics-RootMaster-overlay.patch new file mode 100644 index 00000000000..f16d0bdd29a --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1541-overlays-Add-OpenHydroponics-RootMaster-overlay.patch @@ -0,0 +1,119 @@ +From 081eebdeccfd12e0aaba4b64c9f87b608777913b Mon Sep 17 00:00:00 2001 +From: Micke Prag +Date: Thu, 13 Feb 2025 22:08:43 +0100 +Subject: [PATCH] overlays: Add OpenHydroponics RootMaster overlay + +Signed-off-by: Micke Prag +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 7 ++ + .../boot/dts/overlays/rootmaster-overlay.dts | 77 +++++++++++++++++++ + 3 files changed, 85 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/rootmaster-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -228,6 +228,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + qca7000-uart0.dtbo \ + ramoops.dtbo \ + ramoops-pi4.dtbo \ ++ rootmaster.dtbo \ + rotary-encoder.dtbo \ + rpi-backlight.dtbo \ + rpi-codeczero.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -4084,6 +4084,13 @@ Params: base-addr Where to + console-size Size of non-panic dmesg captures (default 0) + + ++Name: rootmaster ++Info: Overlay for OpenHydroponics RootMaster board. ++ https://openhydroponics.com/hw/rootmaster ++Load: dtoverlay=rootmaster ++Params: ++ ++ + Name: rotary-encoder + Info: Overlay for GPIO connected rotary encoder. + Load: dtoverlay=rotary-encoder,= +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rootmaster-overlay.dts +@@ -0,0 +1,77 @@ ++// redo: ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 w1-gpio-overlay.dts,gpiopin=4 ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ fragment@0 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ mcp251xfd_pins: mcp251xfd_spi0_0_pins { ++ brcm,pins = <25>; ++ brcm,function = ; ++ }; ++ }; ++ }; ++ fragment@2 { ++ target-path = "/clocks"; ++ __overlay__ { ++ clk_mcp251xfd_osc: mcp251xfd-spi0-0-osc { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <40000000>; ++ }; ++ }; ++ }; ++ fragment@3 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ mcp251xfd@0 { ++ compatible = "microchip,mcp251xfd"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mcp251xfd_pins>; ++ spi-max-frequency = <20000000>; ++ interrupt-parent = <&gpio>; ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; ++ clocks = <&clk_mcp251xfd_osc>; ++ }; ++ }; ++ }; ++ fragment@4 { ++ target-path = "/"; ++ __overlay__ { ++ onewire@4 { ++ compatible = "w1-gpio"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&w1_pins>; ++ gpios = <&gpio 4 0>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ fragment@5 { ++ target = <&gpio>; ++ __overlay__ { ++ w1_pins: w1_pins@4 { ++ brcm,pins = <4>; ++ brcm,function = <0>; ++ brcm,pull = <0>; ++ }; ++ }; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1542-media-i2c-arducam-pivariety-Fix-mutex-init-and-NULL-.patch b/target/linux/bcm27xx/patches-6.6/950-1542-media-i2c-arducam-pivariety-Fix-mutex-init-and-NULL-.patch new file mode 100644 index 00000000000..784ae522f18 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1542-media-i2c-arducam-pivariety-Fix-mutex-init-and-NULL-.patch @@ -0,0 +1,37 @@ +From 011cbf22d7583687ae18690185169e5da0be000a Mon Sep 17 00:00:00 2001 +From: Yuriy Pasichnyk +Date: Tue, 18 Feb 2025 16:20:31 +0200 +Subject: [PATCH] media: i2c: arducam-pivariety: Fix mutex init and NULL + pointer + +The mutex used in arducam-pivariety was not properly initialized, +which could lead to undefined behavior. This also caused a NULL +pointer dereference under certain conditions. + +This patch ensures the mutex is correctly initialized during probe +and prevents NULL pointer dereferences. + +Signed-off-by: Yuriy Pasichnyk +--- + drivers/media/i2c/arducam-pivariety.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/media/i2c/arducam-pivariety.c ++++ b/drivers/media/i2c/arducam-pivariety.c +@@ -1208,6 +1208,8 @@ static int pivariety_enum_controls(struc + if (ret) + return ret; + ++ mutex_init(&pivariety->mutex); ++ + index = 0; + while (1) { + ret = pivariety_write(pivariety, CTRL_INDEX_REG, index); +@@ -1295,6 +1297,7 @@ static int pivariety_enum_controls(struc + v4l2_ctrl_handler_setup(ctrl_hdlr); + return 0; + err: ++ mutex_destroy(&pivariety->mutex); + return -ENODEV; + } + diff --git a/target/linux/bcm27xx/patches-6.6/950-1543-misc-rp1-pio-Demote-fw-probe-error-to-warning.patch b/target/linux/bcm27xx/patches-6.6/950-1543-misc-rp1-pio-Demote-fw-probe-error-to-warning.patch new file mode 100644 index 00000000000..af9c9f9e529 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1543-misc-rp1-pio-Demote-fw-probe-error-to-warning.patch @@ -0,0 +1,32 @@ +From af9965a855a8c6c7140bbcccfa89eec7e90a993d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 25 Feb 2025 12:16:33 +0000 +Subject: [PATCH] misc: rp1-pio: Demote fw probe error to warning + +Support for the RP1 firmware mailbox API is rolling out to Pi 5 EEPROM +images. For most users, the fact that the PIO is not available is no +cause for alarm. Change the message to a warning, so that it does not +appear with "quiet" in cmdline.txt. + +Link: https://github.com/raspberrypi/linux/issues/6642 + +Signed-off-by: Phil Elwell +--- + drivers/misc/rp1-pio.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/misc/rp1-pio.c ++++ b/drivers/misc/rp1-pio.c +@@ -1279,8 +1279,10 @@ static int rp1_pio_probe(struct platform + fw = devm_rp1_firmware_get(dev, dev->of_node); + if (!fw) + return dev_err_probe(dev, -EPROBE_DEFER, "failed to find RP1 firmware driver\n"); +- if (IS_ERR(fw)) +- return dev_err_probe(dev, PTR_ERR(fw), "failed to contact RP1 firmware\n"); ++ if (IS_ERR(fw)) { ++ dev_warn(dev, "failed to contact RP1 firmware\n"); ++ return PTR_ERR(fw); ++ } + ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count); + if (ret < 0) + return ret; diff --git a/target/linux/bcm27xx/patches-6.6/950-1544-dts-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch b/target/linux/bcm27xx/patches-6.6/950-1544-dts-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch new file mode 100644 index 00000000000..98eaf56ee69 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1544-dts-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch @@ -0,0 +1,38 @@ +From a4e7897eef1ad4628572a6abfd30291209a0bf43 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Tue, 25 Feb 2025 15:06:23 +0000 +Subject: [PATCH] dts: Add hogs for RP1 GPIO 46/48 on CM5 + +On Pi5 5, GPIOs 46/48 are made available on the 'CAM/DISP 1' connector as +'CD1_IO0_MICCLK'/'CD1_IO1_MICDAT1'. These GPIOs are not connected on +CM5. + +Add hogs for GPIO 46/48 on CM5 to prevent camera drivers from +inadvertently using them when connected to 'CAM/DISP 1' + +Signed-off-by: Richard Oliver +--- + arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +@@ -734,6 +734,18 @@ spi10_cs_pins: &spi10_cs_gpio1 {}; + function = "vbus1"; + pins = "gpio42", "gpio43"; + }; ++ ++ micclk1_hog { ++ gpio-hog; ++ gpios = <46 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++ ++ micdat1_hog { ++ gpio-hog; ++ gpios = <48 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; + }; + + / { diff --git a/target/linux/bcm27xx/patches-6.6/950-1545-spi-rp2040-gpio-bridge-fix-gpiod-error-handling.patch b/target/linux/bcm27xx/patches-6.6/950-1545-spi-rp2040-gpio-bridge-fix-gpiod-error-handling.patch new file mode 100644 index 00000000000..31e35a3bf2d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1545-spi-rp2040-gpio-bridge-fix-gpiod-error-handling.patch @@ -0,0 +1,25 @@ +From f8f3e202fb083906fbc98ef6ea445e424779c076 Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Tue, 25 Feb 2025 15:22:46 +0000 +Subject: [PATCH] spi: rp2040-gpio-bridge: fix gpiod error handling + +In some circumstances, devm_gpiod_get_array_optional() can return +PTR_ERR rather than NULL to indicate failure. Handle these cases. + +Signed-off-by: Richard Oliver +--- + drivers/spi/spi-rp2040-gpio-bridge.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-rp2040-gpio-bridge.c ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -956,7 +956,8 @@ static void rp2040_gbdg_parse_dt(struct + + rp2040_gbdg->fast_xfer_gpios = + devm_gpiod_get_array_optional(dev, "fast_xfer", GPIOD_ASIS); +- if (!rp2040_gbdg->fast_xfer_gpios) { ++ if (IS_ERR_OR_NULL(rp2040_gbdg->fast_xfer_gpios)) { ++ rp2040_gbdg->fast_xfer_gpios = NULL; + dev_info(dev, "Could not acquire fast_xfer-gpios\n"); + goto node_put; + } diff --git a/target/linux/bcm27xx/patches-6.6/950-1546-spi-rp2040-gpio-bridge-probe-Cfg-fast_xfer-clk.patch b/target/linux/bcm27xx/patches-6.6/950-1546-spi-rp2040-gpio-bridge-probe-Cfg-fast_xfer-clk.patch new file mode 100644 index 00000000000..04b9ea60254 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1546-spi-rp2040-gpio-bridge-probe-Cfg-fast_xfer-clk.patch @@ -0,0 +1,37 @@ +From 2e071057fded90e789c0101498e45a1778be93fe Mon Sep 17 00:00:00 2001 +From: Richard Oliver +Date: Tue, 25 Feb 2025 15:27:59 +0000 +Subject: [PATCH] spi: rp2040-gpio-bridge: probe: Cfg fast_xfer clk + +Fast transfer mode requires that the first bit of data is clocked with a +rising edge. This can cause extra bits of data to be clocked on hardware +where the clock signal uses a pull-up. This change ensures that clk is +driven low before fast data transfer mode is entered. + +Signed-off-by: Richard Oliver +--- + drivers/spi/spi-rp2040-gpio-bridge.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-rp2040-gpio-bridge.c ++++ b/drivers/spi/spi-rp2040-gpio-bridge.c +@@ -617,7 +617,6 @@ static int rp2040_gbdg_fast_xfer(struct + &clock_mux); + + gpiod_direction_output(priv_data->fast_xfer_gpios->desc[0], 1); +- gpiod_direction_output(priv_data->fast_xfer_gpios->desc[1], 0); + + rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_data_index, + &data_bank, &data_offset); +@@ -989,6 +988,11 @@ static void rp2040_gbdg_parse_dt(struct + goto node_put; + } + ++ /* ++ * fast_xfer mode requires first data bit to be clocked on a rising ++ * edge. Configure as output-low here before fast_xfer mode is entered. ++ */ ++ gpiod_direction_output(rp2040_gbdg->fast_xfer_gpios->desc[1], 0); + node_put: + if (of_args[0].np) + of_node_put(of_args[0].np); diff --git a/target/linux/bcm27xx/patches-6.6/950-1547-fix-clang-compilation-error.patch b/target/linux/bcm27xx/patches-6.6/950-1547-fix-clang-compilation-error.patch new file mode 100644 index 00000000000..13fa24beaf5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1547-fix-clang-compilation-error.patch @@ -0,0 +1,30 @@ +From 1337c39626c14ca5e61b4cddbc097d87212a0b13 Mon Sep 17 00:00:00 2001 +From: KubaTaba1uga +Date: Mon, 3 Mar 2025 17:25:29 +0100 +Subject: [PATCH] fix clang compilation error + +--- + drivers/dma-buf/heaps/system_heap.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/dma-buf/heaps/system_heap.c ++++ b/drivers/dma-buf/heaps/system_heap.c +@@ -50,11 +50,16 @@ static gfp_t order_flags[] = {HIGH_ORDER + * to match with the sizes often found in IOMMUs. Using order 4 pages instead + * of order 0 pages can significantly improve the performance of many IOMMUs + * by reducing TLB pressure and time spent updating page tables. ++ * ++ * Note: `module_max_order` must be set explicitly instead of using ++ * `orders[0]` to avoid Clang's "initializer element is not a ++ * compile-time constant" error. + */ +-static const unsigned int orders[] = {8, 4, 0}; ++#define MAX_ORDERS_VALUE 8 ++static const unsigned int orders[] = {MAX_ORDERS_VALUE, 4, 0}; + #define NUM_ORDERS ARRAY_SIZE(orders) + +-static unsigned int module_max_order = orders[0]; ++static unsigned int module_max_order = MAX_ORDERS_VALUE; + + module_param_named(max_order, module_max_order, uint, 0400); + MODULE_PARM_DESC(max_order, "Maximum allocation order override."); diff --git a/target/linux/bcm27xx/patches-6.6/950-1548-delete-the-comment.patch b/target/linux/bcm27xx/patches-6.6/950-1548-delete-the-comment.patch new file mode 100644 index 00000000000..0918f8cded1 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1548-delete-the-comment.patch @@ -0,0 +1,22 @@ +From f1076a9d7a269d72b6707283560d0d38203cb07a Mon Sep 17 00:00:00 2001 +From: KubaTaba1uga +Date: Tue, 4 Mar 2025 09:50:30 +0100 +Subject: [PATCH] delete the comment + +--- + drivers/dma-buf/heaps/system_heap.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/dma-buf/heaps/system_heap.c ++++ b/drivers/dma-buf/heaps/system_heap.c +@@ -50,10 +50,6 @@ static gfp_t order_flags[] = {HIGH_ORDER + * to match with the sizes often found in IOMMUs. Using order 4 pages instead + * of order 0 pages can significantly improve the performance of many IOMMUs + * by reducing TLB pressure and time spent updating page tables. +- * +- * Note: `module_max_order` must be set explicitly instead of using +- * `orders[0]` to avoid Clang's "initializer element is not a +- * compile-time constant" error. + */ + #define MAX_ORDERS_VALUE 8 + static const unsigned int orders[] = {MAX_ORDERS_VALUE, 4, 0}; diff --git a/target/linux/bcm27xx/patches-6.6/950-1549-dtoverlays-ov9281-Add-continuous-clock-option-as-an-.patch b/target/linux/bcm27xx/patches-6.6/950-1549-dtoverlays-ov9281-Add-continuous-clock-option-as-an-.patch new file mode 100644 index 00000000000..a2b7df78d9c --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1549-dtoverlays-ov9281-Add-continuous-clock-option-as-an-.patch @@ -0,0 +1,66 @@ +From ac56a225e0889e60e912ecd3a51333a5aee901fc Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 4 Mar 2025 15:28:53 +0000 +Subject: [PATCH] dtoverlays: ov9281: Add continuous clock option as an + override + +The previous change to make ov9281 always run in continuous clock +mode causes problems on Pi3 for reasons that aren't fully +understood. Pi4 is quite happy with it. + +Change the default back to being non-continuous clock, and add +an override to select continuous clock mode and its slightly +greater max frame rate. + +https://forums.raspberrypi.com/viewtopic.php?p=2300215 + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 3 +++ + arch/arm/boot/dts/overlays/ov9281-overlay.dts | 16 +++++++++++++++- + 2 files changed, 18 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -3570,6 +3570,9 @@ Params: rotation Mounting + Compute Module (CSI0, i2c_vc, and cam0_reg). + arducam Slow down the regulator for slow Arducam + modules. ++ clk-continuous Switch to continuous mode on the CSI clock lane, ++ which increases the maximum frame rate slightly. ++ Appears not to work on Pi3. + + + Name: papirus +--- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts ++++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts +@@ -64,6 +64,20 @@ + }; + }; + ++ fragment@6 { ++ target = <&csi_ep>; ++ __overlay__ { ++ clock-noncontinuous; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&cam_endpoint>; ++ __overlay__ { ++ clock-noncontinuous; ++ }; ++ }; ++ + __overrides__ { + rotation = <&cam_node>,"rotation:0"; + orientation = <&cam_node>,"orientation:0"; +@@ -75,7 +89,7 @@ + <&cam_node>, "avdd-supply:0=",<&cam0_reg>, + <®_frag>, "target:0=",<&cam0_reg>; + arducam = <0>, "+5"; +- ++ clk-continuous = <0>, "-6-7"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1550-drm-v3d-Add-clock-handling.patch b/target/linux/bcm27xx/patches-6.6/950-1550-drm-v3d-Add-clock-handling.patch new file mode 100644 index 00000000000..3bce057bfdc --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1550-drm-v3d-Add-clock-handling.patch @@ -0,0 +1,129 @@ +From 32c319ba2f2fd662a3b7bd042515cd650807dbff Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Sat, 1 Feb 2025 13:50:46 +0100 +Subject: [PATCH] drm/v3d: Add clock handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit 4dd40b5f9c3d89b67af0dbe059cf4a51aac6bf06 ] + +Since the initial commit 57692c94dcbe ("drm/v3d: Introduce a new DRM driver +for Broadcom V3D V3.x+") the struct v3d_dev reserved a pointer for +an optional V3D clock. But there wasn't any code, which fetched it. +So add the missing clock handling before accessing any V3D registers. + +Signed-off-by: Stefan Wahren +Reviewed-by: Maíra Canal +Signed-off-by: Maíra Canal +Link: https://patchwork.freedesktop.org/patch/msgid/20250201125046.33030-1-wahrenst@gmx.net +[ Maíra: Backported to the downstream repository ] +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/v3d/v3d_drv.c | 44 ++++++++++++++++++++++------------- + 1 file changed, 28 insertions(+), 16 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -232,11 +232,21 @@ static int v3d_platform_drm_probe(struct + if (ret) + return ret; + ++ v3d->clk = devm_clk_get_optional(dev, NULL); ++ if (IS_ERR(v3d->clk)) ++ return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n"); ++ ++ ret = clk_prepare_enable(v3d->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "Couldn't enable the V3D clock\n"); ++ return ret; ++ } ++ + mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); + mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); + ret = dma_set_mask_and_coherent(dev, mask); + if (ret) +- return ret; ++ goto clk_disable; + + v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); + +@@ -251,32 +261,29 @@ static int v3d_platform_drm_probe(struct + ret = PTR_ERR(v3d->reset); + + if (ret == -EPROBE_DEFER) +- return ret; ++ goto clk_disable; + + v3d->reset = NULL; + ret = map_regs(v3d, &v3d->bridge_regs, "bridge"); + if (ret) { + dev_err(dev, + "Failed to get reset control or bridge regs\n"); +- return ret; ++ goto clk_disable; + } + } + +- v3d->clk = devm_clk_get(dev, NULL); +- if (IS_ERR_OR_NULL(v3d->clk)) { +- if (PTR_ERR(v3d->clk) != -EPROBE_DEFER) +- dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk)); +- return PTR_ERR(v3d->clk); +- } +- + node = rpi_firmware_find_node(); +- if (!node) +- return -EINVAL; ++ if (!node) { ++ ret = -EINVAL; ++ goto clk_disable; ++ } + + firmware = rpi_firmware_get(node); + of_node_put(node); +- if (!firmware) +- return -EPROBE_DEFER; ++ if (!firmware) { ++ ret = -EPROBE_DEFER; ++ goto clk_disable; ++ } + + v3d->clk_up_rate = rpi_firmware_clk_get_max_rate(firmware, + RPI_FIRMWARE_V3D_CLK_ID); +@@ -293,14 +300,15 @@ static int v3d_platform_drm_probe(struct + if (v3d->ver < 41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) +- return ret; ++ goto clk_disable; + } + + v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!v3d->mmu_scratch) { + dev_err(dev, "Failed to allocate MMU scratch page\n"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto clk_disable; + } + + ret = v3d_gem_init(drm); +@@ -326,6 +334,8 @@ gem_destroy: + v3d_gem_destroy(drm); + dma_free: + dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr); ++clk_disable: ++ clk_disable_unprepare(v3d->clk); + return ret; + } + +@@ -340,6 +350,8 @@ static void v3d_platform_drm_remove(stru + + dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch, + v3d->mmu_scratch_paddr); ++ ++ clk_disable_unprepare(v3d->clk); + } + + static struct platform_driver v3d_platform_driver = { diff --git a/target/linux/bcm27xx/patches-6.6/950-1551-drm-v3d-Don-t-run-jobs-that-have-errors-flagged-in-i.patch b/target/linux/bcm27xx/patches-6.6/950-1551-drm-v3d-Don-t-run-jobs-that-have-errors-flagged-in-i.patch new file mode 100644 index 00000000000..cdb9ad18880 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1551-drm-v3d-Don-t-run-jobs-that-have-errors-flagged-in-i.patch @@ -0,0 +1,61 @@ +From 5258ca4ad089548a72657522443b9c3e46fd125b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Sat, 22 Feb 2025 14:40:21 -0300 +Subject: [PATCH] drm/v3d: Don't run jobs that have errors flagged in its fence +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The V3D driver still relies on `drm_sched_increase_karma()` and +`drm_sched_resubmit_jobs()` for resubmissions when a timeout occurs. +The function `drm_sched_increase_karma()` marks the job as guilty, while +`drm_sched_resubmit_jobs()` sets an error (-ECANCELED) in the DMA fence of +that guilty job. + +Because of this, we must check whether the job’s DMA fence has been +flagged with an error before executing the job. Otherwise, the same guilty +job may be resubmitted indefinitely, causing repeated GPU resets. + +This patch adds a check for an error on the job's fence to prevent running +a guilty job that was previously flagged when the GPU timed out. + +Note that the CPU and CACHE_CLEAN queues do not require this check, as +their jobs are executed synchronously once the DRM scheduler starts them. + +Cc: stable@vger.kernel.org +Fixes: d223f98f0209 ("drm/v3d: Add support for compute shader dispatch.") +Fixes: 1584f16ca96e ("drm/v3d: Add support for submitting jobs to the TFU.") +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/v3d/v3d_sched.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -292,11 +292,15 @@ v3d_tfu_job_run(struct drm_sched_job *sc + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; + ++ if (unlikely(job->base.base.s_fence->finished.error)) ++ return NULL; ++ ++ v3d->tfu_job = job; ++ + fence = v3d_fence_create(v3d, V3D_TFU); + if (IS_ERR(fence)) + return NULL; + +- v3d->tfu_job = job; + if (job->base.irq_fence) + dma_fence_put(job->base.irq_fence); + job->base.irq_fence = dma_fence_get(fence); +@@ -333,6 +337,9 @@ v3d_csd_job_run(struct drm_sched_job *sc + struct dma_fence *fence; + int i, csd_cfg0_reg, csd_cfg_reg_count; + ++ if (unlikely(job->base.base.s_fence->finished.error)) ++ return NULL; ++ + v3d->csd_job = job; + + v3d_invalidate_caches(v3d); diff --git a/target/linux/bcm27xx/patches-6.6/950-1552-drm-v3d-Set-job-pointer-to-NULL-when-the-job-s-fence.patch b/target/linux/bcm27xx/patches-6.6/950-1552-drm-v3d-Set-job-pointer-to-NULL-when-the-job-s-fence.patch new file mode 100644 index 00000000000..3bf33ffc757 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1552-drm-v3d-Set-job-pointer-to-NULL-when-the-job-s-fence.patch @@ -0,0 +1,84 @@ +From 131564261399a36a5cf2ac2731ed1ceffba93d10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Sat, 22 Feb 2025 14:56:46 -0300 +Subject: [PATCH] drm/v3d: Set job pointer to NULL when the job's fence has an + error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar to commit e4b5ccd392b9 ("drm/v3d: Ensure job pointer is set to +NULL after job completion"), ensure the job pointer is set to `NULL` when +a job's fence has an error. Failing to do so can trigger kernel warnings +in specific scenarios, such as: + +1. v3d_csd_job_run() assigns `v3d->csd_job = job` +2. CSD job exceeds hang limit, causing a timeout → v3d_gpu_reset_for_timeout() +3. GPU reset +4. drm_sched_resubmit_jobs() sets the job's fence to `-ECANCELED`. +5. v3d_csd_job_run() detects the fence error and returns NULL, not + submitting the job to the GPU +6. User-space runs `modprobe -r v3d` +7. v3d_gem_destroy() + +v3d_gem_destroy() triggers a warning indicating that the CSD job never +ended, as we didn't set `v3d->csd_job` to NULL after the timeout. The same +can also happen to BIN, RENDER, and TFU jobs. + +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/v3d/v3d_sched.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -189,8 +189,12 @@ static struct dma_fence *v3d_bin_job_run + struct dma_fence *fence; + unsigned long irqflags; + +- if (unlikely(job->base.base.s_fence->finished.error)) ++ if (unlikely(job->base.base.s_fence->finished.error)) { ++ spin_lock_irqsave(&v3d->job_lock, irqflags); ++ v3d->bin_job = NULL; ++ spin_unlock_irqrestore(&v3d->job_lock, irqflags); + return NULL; ++ } + + /* Lock required around bin_job update vs + * v3d_overflow_mem_work(). +@@ -244,8 +248,10 @@ static struct dma_fence *v3d_render_job_ + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; + +- if (unlikely(job->base.base.s_fence->finished.error)) ++ if (unlikely(job->base.base.s_fence->finished.error)) { ++ v3d->render_job = NULL; + return NULL; ++ } + + v3d->render_job = job; + +@@ -292,8 +298,10 @@ v3d_tfu_job_run(struct drm_sched_job *sc + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; + +- if (unlikely(job->base.base.s_fence->finished.error)) ++ if (unlikely(job->base.base.s_fence->finished.error)) { ++ v3d->tfu_job = NULL; + return NULL; ++ } + + v3d->tfu_job = job; + +@@ -337,8 +345,10 @@ v3d_csd_job_run(struct drm_sched_job *sc + struct dma_fence *fence; + int i, csd_cfg0_reg, csd_cfg_reg_count; + +- if (unlikely(job->base.base.s_fence->finished.error)) ++ if (unlikely(job->base.base.s_fence->finished.error)) { ++ v3d->csd_job = NULL; + return NULL; ++ } + + v3d->csd_job = job; + diff --git a/target/linux/bcm27xx/patches-6.6/950-1553-drm-v3d-Associate-a-V3D-tech-revision-to-all-support.patch b/target/linux/bcm27xx/patches-6.6/950-1553-drm-v3d-Associate-a-V3D-tech-revision-to-all-support.patch new file mode 100644 index 00000000000..a13516a04ea --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1553-drm-v3d-Associate-a-V3D-tech-revision-to-all-support.patch @@ -0,0 +1,447 @@ +From 97988373018e7fa7ff33b7774f88d30e48f71509 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Tue, 25 Feb 2025 20:44:59 -0300 +Subject: [PATCH] drm/v3d: Associate a V3D tech revision to all supported + devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The V3D driver currently determines the GPU tech version (33, 41...) +by reading a register. This approach has worked so far since this +information wasn’t needed before powering on the GPU. + +V3D 7.1 introduces new registers that must be written to power on the +GPU, requiring us to know the V3D version beforehand. To address this, +associate each supported SoC with the corresponding VideoCore GPU version +as part of the device data. + +To prevent possible mistakes, add an assertion to verify that the version +specified in the device data matches the one reported by the hardware. +If there is a mismatch, the kernel will trigger a warning. + +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/v3d/v3d_debugfs.c | 128 +++++++++++++++--------------- + drivers/gpu/drm/v3d/v3d_drv.c | 22 +++-- + drivers/gpu/drm/v3d/v3d_drv.h | 11 ++- + drivers/gpu/drm/v3d/v3d_gem.c | 12 +-- + drivers/gpu/drm/v3d/v3d_irq.c | 10 +-- + drivers/gpu/drm/v3d/v3d_sched.c | 12 +-- + 6 files changed, 106 insertions(+), 89 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_debugfs.c ++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c +@@ -22,74 +22,74 @@ struct v3d_reg_def { + }; + + static const struct v3d_reg_def v3d_hub_reg_defs[] = { +- REGDEF(33, 42, V3D_HUB_AXICFG), +- REGDEF(33, 71, V3D_HUB_UIFCFG), +- REGDEF(33, 71, V3D_HUB_IDENT0), +- REGDEF(33, 71, V3D_HUB_IDENT1), +- REGDEF(33, 71, V3D_HUB_IDENT2), +- REGDEF(33, 71, V3D_HUB_IDENT3), +- REGDEF(33, 71, V3D_HUB_INT_STS), +- REGDEF(33, 71, V3D_HUB_INT_MSK_STS), +- +- REGDEF(33, 71, V3D_MMU_CTL), +- REGDEF(33, 71, V3D_MMU_VIO_ADDR), +- REGDEF(33, 71, V3D_MMU_VIO_ID), +- REGDEF(33, 71, V3D_MMU_DEBUG_INFO), +- +- REGDEF(71, 71, V3D_V7_GMP_STATUS), +- REGDEF(71, 71, V3D_V7_GMP_CFG), +- REGDEF(71, 71, V3D_V7_GMP_VIO_ADDR), ++ REGDEF(V3D_GEN_33, V3D_GEN_42, V3D_HUB_AXICFG), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_UIFCFG), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT0), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT1), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT2), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT3), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_INT_STS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_INT_MSK_STS), ++ ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_CTL), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_VIO_ADDR), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_VIO_ID), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_DEBUG_INFO), ++ ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_STATUS), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_CFG), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_VIO_ADDR), + }; + + static const struct v3d_reg_def v3d_gca_reg_defs[] = { +- REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN), +- REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK), ++ REGDEF(V3D_GEN_33, V3D_GEN_33, V3D_GCA_SAFE_SHUTDOWN), ++ REGDEF(V3D_GEN_33, V3D_GEN_33, V3D_GCA_SAFE_SHUTDOWN_ACK), + }; + + static const struct v3d_reg_def v3d_core_reg_defs[] = { +- REGDEF(33, 71, V3D_CTL_IDENT0), +- REGDEF(33, 71, V3D_CTL_IDENT1), +- REGDEF(33, 71, V3D_CTL_IDENT2), +- REGDEF(33, 71, V3D_CTL_MISCCFG), +- REGDEF(33, 71, V3D_CTL_INT_STS), +- REGDEF(33, 71, V3D_CTL_INT_MSK_STS), +- REGDEF(33, 71, V3D_CLE_CT0CS), +- REGDEF(33, 71, V3D_CLE_CT0CA), +- REGDEF(33, 71, V3D_CLE_CT0EA), +- REGDEF(33, 71, V3D_CLE_CT1CS), +- REGDEF(33, 71, V3D_CLE_CT1CA), +- REGDEF(33, 71, V3D_CLE_CT1EA), +- +- REGDEF(33, 71, V3D_PTB_BPCA), +- REGDEF(33, 71, V3D_PTB_BPCS), +- +- REGDEF(33, 41, V3D_GMP_STATUS), +- REGDEF(33, 41, V3D_GMP_CFG), +- REGDEF(33, 41, V3D_GMP_VIO_ADDR), +- +- REGDEF(33, 71, V3D_ERR_FDBGO), +- REGDEF(33, 71, V3D_ERR_FDBGB), +- REGDEF(33, 71, V3D_ERR_FDBGS), +- REGDEF(33, 71, V3D_ERR_STAT), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT0), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT1), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT2), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_MISCCFG), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_INT_STS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_INT_MSK_STS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0CS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0CA), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0EA), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1CS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1CA), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1EA), ++ ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_PTB_BPCA), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_PTB_BPCS), ++ ++ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_STATUS), ++ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_CFG), ++ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_VIO_ADDR), ++ ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGO), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGB), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGS), ++ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_STAT), + }; + + static const struct v3d_reg_def v3d_csd_reg_defs[] = { +- REGDEF(41, 71, V3D_CSD_STATUS), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG0), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG1), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG2), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG3), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG4), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG5), +- REGDEF(41, 41, V3D_CSD_CURRENT_CFG6), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG0), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG1), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG2), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG3), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG4), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG5), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG6), +- REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7), ++ REGDEF(V3D_GEN_41, V3D_GEN_71, V3D_CSD_STATUS), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG0), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG1), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG2), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG3), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG4), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG5), ++ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG6), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG0), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG1), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG2), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG3), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG4), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG5), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG6), ++ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG7), + }; + + static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) +@@ -165,7 +165,7 @@ static int v3d_v3d_debugfs_ident(struct + str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU)); + seq_printf(m, "TFU: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU)); +- if (v3d->ver <= 42) { ++ if (v3d->ver <= V3D_GEN_42) { + seq_printf(m, "TSY: %s\n", + str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); + } +@@ -197,11 +197,11 @@ static int v3d_v3d_debugfs_ident(struct + seq_printf(m, " QPUs: %d\n", nslc * qups); + seq_printf(m, " Semaphores: %d\n", + V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM)); +- if (v3d->ver <= 42) { ++ if (v3d->ver <= V3D_GEN_42) { + seq_printf(m, " BCG int: %d\n", + (ident2 & V3D_IDENT2_BCG_INT) != 0); + } +- if (v3d->ver < 40) { ++ if (v3d->ver < V3D_GEN_41) { + seq_printf(m, " Override TMU: %d\n", + (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); + } +@@ -311,8 +311,8 @@ static int v3d_measure_clock(struct seq_ + int core = 0; + int measure_ms = 1000; + +- if (v3d->ver >= 40) { +- int cycle_count_reg = v3d->ver < 71 ? ++ if (v3d->ver >= V3D_GEN_41) { ++ int cycle_count_reg = v3d->ver < V3D_GEN_71 ? + V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT; + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, + V3D_SET_FIELD(cycle_count_reg, +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -88,7 +89,7 @@ static int v3d_get_param_ioctl(struct dr + args->value = 1; + return 0; + case DRM_V3D_PARAM_SUPPORTS_PERFMON: +- args->value = (v3d->ver >= 40); ++ args->value = (v3d->ver >= V3D_GEN_41); + return 0; + case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: + args->value = 1; +@@ -189,10 +190,10 @@ static const struct drm_driver v3d_drm_d + }; + + static const struct of_device_id v3d_of_match[] = { +- { .compatible = "brcm,2712-v3d" }, +- { .compatible = "brcm,2711-v3d" }, +- { .compatible = "brcm,7268-v3d" }, +- { .compatible = "brcm,7278-v3d" }, ++ { .compatible = "brcm,2711-v3d", .data = (void *)V3D_GEN_42 }, ++ { .compatible = "brcm,2712-v3d", .data = (void *)V3D_GEN_71 }, ++ { .compatible = "brcm,7268-v3d", .data = (void *)V3D_GEN_33 }, ++ { .compatible = "brcm,7278-v3d", .data = (void *)V3D_GEN_41 }, + {}, + }; + MODULE_DEVICE_TABLE(of, v3d_of_match); +@@ -211,6 +212,7 @@ static int v3d_platform_drm_probe(struct + struct device_node *node; + struct drm_device *drm; + struct v3d_dev *v3d; ++ enum v3d_gen gen; + int ret; + u32 mmu_debug; + u32 ident1; +@@ -224,6 +226,9 @@ static int v3d_platform_drm_probe(struct + + platform_set_drvdata(pdev, drm); + ++ gen = (enum v3d_gen)of_device_get_match_data(dev); ++ v3d->ver = gen; ++ + ret = map_regs(v3d, &v3d->hub_regs, "hub"); + if (ret) + return ret; +@@ -253,6 +258,11 @@ static int v3d_platform_drm_probe(struct + ident1 = V3D_READ(V3D_HUB_IDENT1); + v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 + + V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV)); ++ /* Make sure that the V3D tech version retrieved from the HW is equal ++ * to the one advertised by the device tree. ++ */ ++ WARN_ON(v3d->ver != gen); ++ + v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES); + WARN_ON(v3d->cores > 1); /* multicore not yet implemented */ + +@@ -297,7 +307,7 @@ static int v3d_platform_drm_probe(struct + v3d->clk_down_rate = + (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000; + +- if (v3d->ver < 41) { ++ if (v3d->ver < V3D_GEN_41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) + goto clk_disable; +--- a/drivers/gpu/drm/v3d/v3d_drv.h ++++ b/drivers/gpu/drm/v3d/v3d_drv.h +@@ -115,13 +115,20 @@ struct v3d_perfmon { + u64 values[]; + }; + ++enum v3d_gen { ++ V3D_GEN_33 = 33, ++ V3D_GEN_41 = 41, ++ V3D_GEN_42 = 42, ++ V3D_GEN_71 = 71, ++}; ++ + struct v3d_dev { + struct drm_device drm; + + /* Short representation (e.g. 33, 41) of the V3D tech version + * and revision. + */ +- int ver; ++ enum v3d_gen ver; + bool single_irq_line; + + void __iomem *hub_regs; +@@ -213,7 +220,7 @@ to_v3d_dev(struct drm_device *dev) + static inline bool + v3d_has_csd(struct v3d_dev *v3d) + { +- return v3d->ver >= 41; ++ return v3d->ver >= V3D_GEN_41; + } + + #define v3d_to_pdev(v3d) to_platform_device((v3d)->drm.dev) +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -69,7 +69,7 @@ v3d_init_core(struct v3d_dev *v3d, int c + * type. If you want the default behavior, you can still put + * "2" in the indirect texture state's output_type field. + */ +- if (v3d->ver < 40) ++ if (v3d->ver < V3D_GEN_41) + V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT); + + /* Whenever we flush the L2T cache, we always want to flush +@@ -89,7 +89,7 @@ v3d_init_hw_state(struct v3d_dev *v3d) + static void + v3d_idle_axi(struct v3d_dev *v3d, int core) + { +- if (v3d->ver >= 71) ++ if (v3d->ver >= V3D_GEN_71) + return; + + V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ); +@@ -105,7 +105,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int co + static void + v3d_idle_gca(struct v3d_dev *v3d) + { +- if (v3d->ver >= 41) ++ if (v3d->ver >= V3D_GEN_41) + return; + + V3D_GCA_WRITE(V3D_GCA_SAFE_SHUTDOWN, V3D_GCA_SAFE_SHUTDOWN_EN); +@@ -179,13 +179,13 @@ v3d_reset(struct v3d_dev *v3d) + static void + v3d_flush_l3(struct v3d_dev *v3d) + { +- if (v3d->ver < 41) { ++ if (v3d->ver < V3D_GEN_41) { + u32 gca_ctrl = V3D_GCA_READ(V3D_GCA_CACHE_CTRL); + + V3D_GCA_WRITE(V3D_GCA_CACHE_CTRL, + gca_ctrl | V3D_GCA_CACHE_CTRL_FLUSH); + +- if (v3d->ver < 33) { ++ if (v3d->ver < V3D_GEN_33) { + V3D_GCA_WRITE(V3D_GCA_CACHE_CTRL, + gca_ctrl & ~V3D_GCA_CACHE_CTRL_FLUSH); + } +@@ -198,7 +198,7 @@ v3d_flush_l3(struct v3d_dev *v3d) + static void + v3d_invalidate_l2c(struct v3d_dev *v3d, int core) + { +- if (v3d->ver > 32) ++ if (v3d->ver >= V3D_GEN_33) + return; + + V3D_CORE_WRITE(core, V3D_CTL_L2CACTL, +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -125,8 +125,8 @@ v3d_irq(int irq, void *arg) + status = IRQ_HANDLED; + } + +- if ((v3d->ver < 71 && (intsts & V3D_INT_CSDDONE)) || +- (v3d->ver >= 71 && (intsts & V3D_V7_INT_CSDDONE))) { ++ if ((v3d->ver < V3D_GEN_71 && (intsts & V3D_INT_CSDDONE)) || ++ (v3d->ver >= V3D_GEN_71 && (intsts & V3D_V7_INT_CSDDONE))) { + struct v3d_fence *fence = + to_v3d_fence(v3d->csd_job->base.irq_fence); + v3d->gpu_queue_stats[V3D_CSD].last_exec_end = local_clock(); +@@ -142,7 +142,7 @@ v3d_irq(int irq, void *arg) + /* We shouldn't be triggering these if we have GMP in + * always-allowed mode. + */ +- if (v3d->ver < 71 && (intsts & V3D_INT_GMPV)) ++ if (v3d->ver < V3D_GEN_71 && (intsts & V3D_INT_GMPV)) + dev_err(v3d->drm.dev, "GMP violation\n"); + + /* V3D 4.2 wires the hub and core IRQs together, so if we & +@@ -200,7 +200,7 @@ v3d_hub_irq(int irq, void *arg) + + V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); + +- if (v3d->ver >= 41) { ++ if (v3d->ver >= V3D_GEN_41) { + axi_id = axi_id >> 5; + if (axi_id < ARRAY_SIZE(v3d41_axi_ids)) + client = v3d41_axi_ids[axi_id]; +@@ -219,7 +219,7 @@ v3d_hub_irq(int irq, void *arg) + status = IRQ_HANDLED; + } + +- if (v3d->ver >= 71 && intsts & V3D_V7_HUB_INT_GMPV) { ++ if (v3d->ver >= V3D_GEN_71 && intsts & V3D_V7_HUB_INT_GMPV) { + dev_err(v3d->drm.dev, "GMP Violation\n"); + status = IRQ_HANDLED; + } +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -288,7 +288,7 @@ static struct dma_fence *v3d_render_job_ + return fence; + } + +-#define V3D_TFU_REG(name) ((v3d->ver < 71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name) ++#define V3D_TFU_REG(name) ((v3d->ver < V3D_GEN_71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name) + + static struct dma_fence * + v3d_tfu_job_run(struct drm_sched_job *sched_job) +@@ -321,11 +321,11 @@ v3d_tfu_job_run(struct drm_sched_job *sc + V3D_WRITE(V3D_TFU_REG(ICA), job->args.ica); + V3D_WRITE(V3D_TFU_REG(IUA), job->args.iua); + V3D_WRITE(V3D_TFU_REG(IOA), job->args.ioa); +- if (v3d->ver >= 71) ++ if (v3d->ver >= V3D_GEN_71) + V3D_WRITE(V3D_V7_TFU_IOC, job->args.v71.ioc); + V3D_WRITE(V3D_TFU_REG(IOS), job->args.ios); + V3D_WRITE(V3D_TFU_REG(COEF0), job->args.coef[0]); +- if (v3d->ver >= 71 || (job->args.coef[0] & V3D_TFU_COEF0_USECOEF)) { ++ if (v3d->ver >= V3D_GEN_71 || (job->args.coef[0] & V3D_TFU_COEF0_USECOEF)) { + V3D_WRITE(V3D_TFU_REG(COEF1), job->args.coef[1]); + V3D_WRITE(V3D_TFU_REG(COEF2), job->args.coef[2]); + V3D_WRITE(V3D_TFU_REG(COEF3), job->args.coef[3]); +@@ -367,8 +367,8 @@ v3d_csd_job_run(struct drm_sched_job *sc + v3d_sched_stats_add_job(&v3d->gpu_queue_stats[V3D_CSD], sched_job); + v3d_switch_perfmon(v3d, &job->base); + +- csd_cfg0_reg = v3d->ver < 71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0; +- csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7; ++ csd_cfg0_reg = v3d->ver < V3D_GEN_71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0; ++ csd_cfg_reg_count = v3d->ver < V3D_GEN_71 ? 6 : 7; + for (i = 1; i <= csd_cfg_reg_count; i++) + V3D_CORE_WRITE(0, csd_cfg0_reg + 4 * i, job->args.cfg[i]); + /* CFG0 write kicks off the job. */ +@@ -475,7 +475,7 @@ v3d_csd_job_timedout(struct drm_sched_jo + { + struct v3d_csd_job *job = to_csd_job(sched_job); + struct v3d_dev *v3d = job->base.v3d; +- u32 batches = V3D_CORE_READ(0, (v3d->ver < 71 ? V3D_CSD_CURRENT_CFG4 : ++ u32 batches = V3D_CORE_READ(0, (v3d->ver < V3D_GEN_71 ? V3D_CSD_CURRENT_CFG4 : + V3D_V7_CSD_CURRENT_CFG4)); + + /* If we've made progress, skip reset and let the timer get diff --git a/target/linux/bcm27xx/patches-6.6/950-1554-dt-bindings-gpu-v3d-Add-SMS-to-the-registers-list.patch b/target/linux/bcm27xx/patches-6.6/950-1554-dt-bindings-gpu-v3d-Add-SMS-to-the-registers-list.patch new file mode 100644 index 00000000000..fb03d82e3f5 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1554-dt-bindings-gpu-v3d-Add-SMS-to-the-registers-list.patch @@ -0,0 +1,43 @@ +From 08e99bc475ad907f3087e4f14c2ddb6560514da1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Sat, 22 Feb 2025 15:26:39 -0300 +Subject: [PATCH] dt-bindings: gpu: v3d: Add SMS to the registers' list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +V3D 7.1 exposes a new register block, called V3D_SMS. As BCM2712 has a +V3D 7.1 core, add a new register item to the list. Similar to the GCA +and bridge register, SMS is optional and should only be added for V3D +7.1 variants. + +Cc: Krzysztof Kozlowski +Cc: Conor Dooley +Cc: Nicolas Saenz Julienne +Cc: devicetree@vger.kernel.org +Signed-off-by: Maíra Canal +--- + Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml ++++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +@@ -27,14 +27,16 @@ properties: + - description: core0 register (required) + - description: GCA cache controller register (if GCA controller present) + - description: bridge register (if no external reset controller) ++ - description: SMS register (if SMS controller present) + minItems: 2 + + reg-names: + items: + - const: hub + - const: core0 +- - enum: [ bridge, gca ] +- - enum: [ bridge, gca ] ++ - enum: [ bridge, gca, sms ] ++ - enum: [ bridge, gca, sms ] ++ - enum: [ bridge, gca, sms ] + minItems: 2 + + interrupts: diff --git a/target/linux/bcm27xx/patches-6.6/950-1555-drm-v3d-Use-V3D_SMS-registers-for-power-on-off-and-r.patch b/target/linux/bcm27xx/patches-6.6/950-1555-drm-v3d-Use-V3D_SMS-registers-for-power-on-off-and-r.patch new file mode 100644 index 00000000000..a39e7242d16 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1555-drm-v3d-Use-V3D_SMS-registers-for-power-on-off-and-r.patch @@ -0,0 +1,198 @@ +From 85e1a7592aa192d760159f9bc6e83d56fdf433f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Sat, 22 Feb 2025 15:49:49 -0300 +Subject: [PATCH] drm/v3d: Use V3D_SMS registers for power on/off and reset on + V3D 7.x +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In addition to the standard reset controller, V3D 7.x requires configuring +the V3D_SMS registers for proper power on/off and reset. Add the new +registers to `v3d_regs.h` and ensure they are properly configured during +device probing, removal, and reset. + +This change fixes GPU reset issues on the Raspberry Pi 5 (BCM2712). +Without exposing these registers, a GPU reset causes the GPU to hang, +stopping any further job execution and freezing the desktop GUI. The same +issue occurs when unloading and loading the v3d driver. + +Link: https://github.com/raspberrypi/linux/issues/6660 +Signed-off-by: Maíra Canal +--- + drivers/gpu/drm/v3d/v3d_drv.c | 40 ++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/v3d/v3d_drv.h | 11 ++++++++++ + drivers/gpu/drm/v3d/v3d_gem.c | 17 +++++++++++++++ + drivers/gpu/drm/v3d/v3d_regs.h | 26 ++++++++++++++++++++++ + 4 files changed, 94 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -198,6 +198,36 @@ static const struct of_device_id v3d_of_ + }; + MODULE_DEVICE_TABLE(of, v3d_of_match); + ++static void ++v3d_idle_sms(struct v3d_dev *v3d) ++{ ++ if (v3d->ver < V3D_GEN_71) ++ return; ++ ++ V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_CLEAR_POWER_OFF); ++ ++ if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), ++ V3D_SMS_STATE) == V3D_SMS_IDLE), 100)) { ++ DRM_ERROR("Failed to power up SMS\n"); ++ } ++ ++ v3d_reset_sms(v3d); ++} ++ ++static void ++v3d_power_off_sms(struct v3d_dev *v3d) ++{ ++ if (v3d->ver < V3D_GEN_71) ++ return; ++ ++ V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_POWER_OFF); ++ ++ if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS), ++ V3D_SMS_STATE) == V3D_SMS_POWER_OFF_STATE), 100)) { ++ DRM_ERROR("Failed to power off SMS\n"); ++ } ++} ++ + static int + map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name) + { +@@ -237,6 +267,12 @@ static int v3d_platform_drm_probe(struct + if (ret) + return ret; + ++ if (v3d->ver >= V3D_GEN_71) { ++ ret = map_regs(v3d, &v3d->sms_regs, "sms"); ++ if (ret) ++ return ret; ++ } ++ + v3d->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(v3d->clk)) + return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n"); +@@ -247,6 +283,8 @@ static int v3d_platform_drm_probe(struct + return ret; + } + ++ v3d_idle_sms(v3d); ++ + mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); + mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); + ret = dma_set_mask_and_coherent(dev, mask); +@@ -361,6 +399,8 @@ static void v3d_platform_drm_remove(stru + dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch, + v3d->mmu_scratch_paddr); + ++ v3d_power_off_sms(v3d); ++ + clk_disable_unprepare(v3d->clk); + } + +--- a/drivers/gpu/drm/v3d/v3d_drv.h ++++ b/drivers/gpu/drm/v3d/v3d_drv.h +@@ -135,6 +135,7 @@ struct v3d_dev { + void __iomem *core_regs[3]; + void __iomem *bridge_regs; + void __iomem *gca_regs; ++ void __iomem *sms_regs; + struct clk *clk; + struct delayed_work clk_down_work; + unsigned long clk_up_rate, clk_down_rate; +@@ -277,6 +278,15 @@ to_v3d_fence(struct dma_fence *fence) + #define V3D_GCA_READ(offset) readl(v3d->gca_regs + offset) + #define V3D_GCA_WRITE(offset, val) writel(val, v3d->gca_regs + offset) + ++#define V3D_SMS_IDLE 0x0 ++#define V3D_SMS_ISOLATING_FOR_RESET 0xa ++#define V3D_SMS_RESETTING 0xb ++#define V3D_SMS_ISOLATING_FOR_POWER_OFF 0xc ++#define V3D_SMS_POWER_OFF_STATE 0xd ++ ++#define V3D_SMS_READ(offset) readl(v3d->sms_regs + (offset)) ++#define V3D_SMS_WRITE(offset, val) writel(val, v3d->sms_regs + (offset)) ++ + #define V3D_CORE_READ(core, offset) readl(v3d->core_regs[core] + offset) + #define V3D_CORE_WRITE(core, offset, val) writel(val, v3d->core_regs[core] + offset) + +@@ -455,6 +465,7 @@ int v3d_wait_bo_ioctl(struct drm_device + struct drm_file *file_priv); + void v3d_job_cleanup(struct v3d_job *job); + void v3d_job_put(struct v3d_job *job); ++void v3d_reset_sms(struct v3d_dev *v3d); + void v3d_reset(struct v3d_dev *v3d); + void v3d_invalidate_caches(struct v3d_dev *v3d); + void v3d_clean_caches(struct v3d_dev *v3d); +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -152,6 +152,22 @@ v3d_reset_v3d(struct v3d_dev *v3d) + } + + void ++v3d_reset_sms(struct v3d_dev *v3d) ++{ ++ if (v3d->ver < V3D_GEN_71) ++ return; ++ ++ V3D_SMS_WRITE(V3D_SMS_REE_CS, V3D_SET_FIELD(0x4, V3D_SMS_STATE)); ++ ++ if (wait_for(!(V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_REE_CS), ++ V3D_SMS_STATE) == V3D_SMS_ISOLATING_FOR_RESET) && ++ !(V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_REE_CS), ++ V3D_SMS_STATE) == V3D_SMS_RESETTING), 100)) { ++ DRM_ERROR("Failed to wait for SMS reset\n"); ++ } ++} ++ ++void + v3d_reset(struct v3d_dev *v3d) + { + struct drm_device *dev = &v3d->drm; +@@ -166,6 +182,7 @@ v3d_reset(struct v3d_dev *v3d) + v3d_idle_axi(v3d, 0); + + v3d_idle_gca(v3d); ++ v3d_reset_sms(v3d); + v3d_reset_v3d(v3d); + + v3d_mmu_set_page_table(v3d); +--- a/drivers/gpu/drm/v3d/v3d_regs.h ++++ b/drivers/gpu/drm/v3d/v3d_regs.h +@@ -543,4 +543,30 @@ + # define V3D_ERR_VPAERGS BIT(1) + # define V3D_ERR_VPAEABB BIT(0) + ++#define V3D_SMS_REE_CS 0x00000 ++#define V3D_SMS_TEE_CS 0x00400 ++# define V3D_SMS_INTERRUPT BIT(31) ++# define V3D_SMS_POWER_OFF BIT(30) ++# define V3D_SMS_CLEAR_POWER_OFF BIT(29) ++# define V3D_SMS_LOCK BIT(28) ++# define V3D_SMS_CLEAR_LOCK BIT(27) ++# define V3D_SMS_SVP_MODE_EXIT BIT(26) ++# define V3D_SMS_CLEAR_SVP_MODE_EXIT BIT(25) ++# define V3D_SMS_SVP_MODE_ENTER BIT(24) ++# define V3D_SMS_CLEAR_SVP_MODE_ENTER BIT(23) ++# define V3D_SMS_THEIR_MODE_EXIT BIT(22) ++# define V3D_SMS_THEIR_MODE_ENTER BIT(21) ++# define V3D_SMS_OUR_MODE_EXIT BIT(20) ++# define V3D_SMS_CLEAR_OUR_MODE_EXIT BIT(19) ++# define V3D_SMS_SEQ_PC_MASK V3D_MASK(16, 10) ++# define V3D_SMS_SEQ_PC_SHIFT 10 ++# define V3D_SMS_HUBCORE_STATUS_MASK V3D_MASK(9, 8) ++# define V3D_SMS_HUBCORE_STATUS_SHIFT 8 ++# define V3D_SMS_NEW_MODE_MASK V3D_MASK(7, 6) ++# define V3D_SMS_NEW_MODE_SHIFT 6 ++# define V3D_SMS_OLD_MODE_MASK V3D_MASK(5, 4) ++# define V3D_SMS_OLD_MODE_SHIFT 4 ++# define V3D_SMS_STATE_MASK V3D_MASK(3, 0) ++# define V3D_SMS_STATE_SHIFT 0 ++ + #endif /* V3D_REGS_H */ diff --git a/target/linux/bcm27xx/patches-6.6/950-1556-dts-bcm2712-Add-V3D_SMS-register.patch b/target/linux/bcm27xx/patches-6.6/950-1556-dts-bcm2712-Add-V3D_SMS-register.patch new file mode 100644 index 00000000000..2d43d1c858d --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1556-dts-bcm2712-Add-V3D_SMS-register.patch @@ -0,0 +1,27 @@ +From 3c21211667e35029054b0dfebdf292e4e7d5754b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ma=C3=ADra=20Canal?= +Date: Thu, 27 Feb 2025 21:00:42 -0300 +Subject: [PATCH] dts: bcm2712: Add V3D_SMS register +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Maíra Canal +--- + arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +@@ -1222,8 +1222,9 @@ + v3d: v3d@2000000 { + compatible = "brcm,2712-v3d"; + reg = <0x10 0x02000000 0x0 0x4000>, +- <0x10 0x02008000 0x0 0x6000>; +- reg-names = "hub", "core0"; ++ <0x10 0x02008000 0x0 0x6000>, ++ <0x10 0x02030800 0x0 0x0700>; ++ reg-names = "hub", "core0", "sms"; + + power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; + resets = <&pm BCM2835_RESET_V3D>; diff --git a/target/linux/bcm27xx/patches-6.6/950-1557-dts-Remove-the-power-key-debounce-on-Pi-500.patch b/target/linux/bcm27xx/patches-6.6/950-1557-dts-Remove-the-power-key-debounce-on-Pi-500.patch new file mode 100644 index 00000000000..faccc79c2ca --- /dev/null +++ b/target/linux/bcm27xx/patches-6.6/950-1557-dts-Remove-the-power-key-debounce-on-Pi-500.patch @@ -0,0 +1,21 @@ +From 08d4e8f52256bd422d8a1f876411603f627d0a82 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 11 Mar 2025 08:58:52 +0000 +Subject: [PATCH] dts: Remove the power key debounce on Pi 500 + +Signed-off-by: Phil Elwell +--- + 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 +@@ -7,7 +7,7 @@ + }; + + &pwr_key { +- debounce-interval = <400>; ++ debounce-interval = <0>; + }; + + &gio {