bcm27xx: pull 6.6 patches from RPi repo
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Sat, 15 Mar 2025 10:43:43 +0000 (11:43 +0100)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Sun, 16 Mar 2025 07:04:48 +0000 (08:04 +0100)
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 <noltari@gmail.com>
65 files changed:
target/linux/bcm27xx/patches-6.6/950-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch [deleted file]
target/linux/bcm27xx/patches-6.6/950-0853-drivers-usb-dwc3-add-FS-LS-bus-instance-parkmode-dis.patch
target/linux/bcm27xx/patches-6.6/950-1359-usb-dwc3-core-add-support-for-setting-NAK-enhancemen.patch
target/linux/bcm27xx/patches-6.6/950-1484-Add-and-update-files-for-pwm-gpio-fan-overlay.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1486-media-i2c-imx290-Limit-analogue-gain-according-to-mo.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1488-media-dt-bindings-sony-imx290-Add-IMX462-to-the-IMX2.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1489-media-i2c-imx290-Add-configuration-for-IMX462.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1490-media-imx290-Add-module-parameter-to-allow-selection.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1491-dtoverlays-Switch-imx462-overlay-to-use-the-new-comp.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1492-media-i2c-imx415-Add-more-clock-configurations.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1494-dtoverlays-Add-overlay-for-Sony-IMX415-image-sensor.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1495-media-i2c-imx415-Add-read-write-control-of-VBLANK.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1496-media-i2c-imx415-Make-HBLANK-controllable-and-in-con.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1497-media-i2c-imx415-Link-frequencies-are-not-exclusive-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1498-dts-bcm2711-PL011-UARTs-are-actually-r1p5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1499-dts-bcm2712-PL011-UARTs-are-actually-r1p5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1500-dts-rp1-PL011-UARTs-are-actually-r1p5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1501-ASoC-pcm512x-Demote-No-SCLK-to-debug-level.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1502-ASoC-allo-piano-dac-plus-Fix-volume-limiting.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1503-ASoC-allo-piano-dac-plus-Remove-pointless-code.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1505-DT-bcm2712-override-supports-cqe-to-a-cell.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1506-mmc-sd-filter-card-CQ-support-based-on-an-allow-list.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1507-mmc-set-MMC_QUIRK_KNOWN_WORKING_SD_CQ-on-Raspberry-P.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1508-mmc-use-downstream-DT-property-to-modify-CQE-and-or-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1509-misc-rp1-pio-Handle-probe-errors.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1510-firmware-rp1-Simplify-rp1_firmware_get.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1512-dts-bcm2711-Don-t-mark-timer-regs-unconfigured.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1513-mmc-bcm2835-sdhost-Observe-SWIOTLB-memory-limit.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1514-drivers-media-pisp_be-Add-support-for-YUV422-planar-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1515-drivers-media-pisp_be-Remove-unused-fields-in-struct.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1516-media-imx219-Adjust-PLL-settings-based-on-the-number.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1517-IMX219-Add-4-lane-option-to-the-device-tree-overlay.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1518-dtoverlays-waveshare-panel-Disable-new-touch-control.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1519-drm-rp1-rp1-dpi-Add-rgb_order-property-to-match-VC4-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1522-add-ina238-to-i2c-sensors.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1524-add-shtc3-to-i2c-sensors.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1525-drivers-media-pci-Update-Hailo-accelerator-device-dr.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1526-overlays-Regularisation-and-improvements.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1527-overlays-Factor-out-the-common-i2c-bus-selection.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1529-misc-rp1-pio-SM_CONFIG_XFER32-larger-DMA-bufs.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1530-spi-dw-Wait-for-idle-after-TX.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1531-misc-rp1-pio-Error-out-on-incompatible-firmware.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1532-firmware-rp1-Linger-on-firmware-failure.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1533-mailbox-rp1-Don-t-claim-channels-in-of_xlate.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1534-fixup-spi-dw-Wait-for-idle-after-TX.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1535-dtoverlays-adds-support-for-Hifiberry-ADC8x-to-the-D.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1536-ASoC-adds-ADC8x-support-to-the-Hifiberry-DAC8x.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1539-Reapply-usb-dwc3-Set-DMA-and-coherent-masks-early.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1541-overlays-Add-OpenHydroponics-RootMaster-overlay.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1542-media-i2c-arducam-pivariety-Fix-mutex-init-and-NULL-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1543-misc-rp1-pio-Demote-fw-probe-error-to-warning.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1544-dts-Add-hogs-for-RP1-GPIO-46-48-on-CM5.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1545-spi-rp2040-gpio-bridge-fix-gpiod-error-handling.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1546-spi-rp2040-gpio-bridge-probe-Cfg-fast_xfer-clk.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1547-fix-clang-compilation-error.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1548-delete-the-comment.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1549-dtoverlays-ov9281-Add-continuous-clock-option-as-an-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1550-drm-v3d-Add-clock-handling.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1551-drm-v3d-Don-t-run-jobs-that-have-errors-flagged-in-i.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1552-drm-v3d-Set-job-pointer-to-NULL-when-the-job-s-fence.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1553-drm-v3d-Associate-a-V3D-tech-revision-to-all-support.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1554-dt-bindings-gpu-v3d-Add-SMS-to-the-registers-list.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1555-drm-v3d-Use-V3D_SMS-registers-for-power-on-off-and-r.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1556-dts-bcm2712-Add-V3D_SMS-register.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-6.6/950-1557-dts-Remove-the-power-key-debounce-on-Pi-500.patch [new file with mode: 0644]

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-0519-usb-dwc3-Set-DMA-and-coherent-masks-early.patch
deleted file mode 100644 (file)
index a087faa..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-From fa846f5991de6c37db1f40e26a39f52c130f2bc7 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.com>
-Date: Mon, 13 Sep 2021 11:14:32 +0100
-Subject: [PATCH 0519/1085] 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 <jonathan@raspberrypi.com>
-
-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 <jonathan@raspberrypi.com>
-
-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 <jonathan@raspberrypi.com>
-
-drivers: usb: dwc3: remove downstream quirk dis-in-autoretry
-
-Upstream have unilaterally disabled the feature.
-
-Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream)
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
----
- drivers/phy/broadcom/Kconfig                  |  2 +-
- .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++
- drivers/phy/broadcom/phy-brcm-usb-init.h      |  2 +
- drivers/phy/broadcom/phy-brcm-usb.c           | 18 +++++-
- drivers/usb/dwc3/core.c                       | 53 +++++++++++++++++
- drivers/usb/dwc3/core.h                       |  5 ++
- drivers/usb/dwc3/host.c                       |  9 ++-
- 7 files changed, 145 insertions(+), 3 deletions(-)
-
---- a/drivers/phy/broadcom/Kconfig
-+++ b/drivers/phy/broadcom/Kconfig
-@@ -93,7 +93,7 @@ config PHY_BRCM_SATA
- config PHY_BRCM_USB
-       tristate "Broadcom STB USB PHY driver"
--      depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST
-+      depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
-       depends on OF
-       select GENERIC_PHY
-       select SOC_BRCMSTB if ARCH_BRCMSTB
---- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
-+++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
-@@ -341,6 +341,36 @@ static void usb_init_common_7216(struct
-       usb_init_common(params);
- }
-+static void usb_init_common_2712(struct brcm_usb_init_params *params)
-+{
-+      void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
-+      void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
-+      u32 reg;
-+
-+      if (params->syscon_piarbctl)
-+              syscon_piarbctl_init(params->syscon_piarbctl);
-+
-+      USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
-+
-+      usb_wake_enable_7211b0(params, false);
-+
-+      usb_init_common(params);
-+
-+      /*
-+       * The BDC controller will get occasional failures with
-+       * the default "Read Transaction Size" of 6 (1024 bytes).
-+       * Set it to 4 (256 bytes).
-+       */
-+      if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) {
-+              reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
-+              reg &= ~BDC_EC_AXIRDA_RTS_MASK;
-+              reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
-+              brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
-+      }
-+
-+      usb2_eye_fix_7211b0(params);
-+}
-+
- static void usb_init_xhci(struct brcm_usb_init_params *params)
- {
-       pr_debug("%s\n", __func__);
-@@ -386,6 +416,18 @@ static void usb_uninit_common_7211b0(str
- }
-+static void usb_uninit_common_2712(struct brcm_usb_init_params *params)
-+{
-+      void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
-+
-+      if (params->wake_enabled) {
-+              USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
-+              usb_wake_enable_7211b0(params, true);
-+      } else {
-+              USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
-+      }
-+}
-+
- static void usb_uninit_xhci(struct brcm_usb_init_params *params)
- {
-@@ -440,6 +482,16 @@ static const struct brcm_usb_init_ops bc
-       .set_dual_select = usb_set_dual_select,
- };
-+static const struct brcm_usb_init_ops bcm2712_ops = {
-+      .init_ipp = usb_init_ipp,
-+      .init_common = usb_init_common_2712,
-+      .init_xhci = usb_init_xhci,
-+      .uninit_common = usb_uninit_common_2712,
-+      .uninit_xhci = usb_uninit_xhci,
-+      .get_dual_select = usb_get_dual_select,
-+      .set_dual_select = usb_set_dual_select,
-+};
-+
- void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
- {
-@@ -457,3 +509,10 @@ void brcm_usb_dvr_init_7211b0(struct brc
-       params->family_name = "7211";
-       params->ops = &bcm7211b0_ops;
- }
-+
-+void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params)
-+{
-+      params->family_name = "2712";
-+      params->ops = &bcm2712_ops;
-+      params->suspend_with_clocks = true;
-+}
---- a/drivers/phy/broadcom/phy-brcm-usb-init.h
-+++ b/drivers/phy/broadcom/phy-brcm-usb-init.h
-@@ -70,12 +70,14 @@ struct  brcm_usb_init_params {
-       const struct brcm_usb_init_ops *ops;
-       struct regmap *syscon_piarbctl;
-       bool wake_enabled;
-+      bool suspend_with_clocks;
- };
- void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
- void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
- void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
- void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params);
-+void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params);
- static inline u32 brcm_usb_readl(void __iomem *addr)
- {
---- a/drivers/phy/broadcom/phy-brcm-usb.c
-+++ b/drivers/phy/broadcom/phy-brcm-usb.c
-@@ -75,7 +75,7 @@ struct brcm_usb_phy_data {
- };
- static s8 *node_reg_names[BRCM_REGS_MAX] = {
--      "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
-+      "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
- };
- static int brcm_pm_notifier(struct notifier_block *notifier,
-@@ -315,6 +315,18 @@ static const struct match_chip_info chip
-       .optional_reg = BRCM_REGS_BDC_EC,
- };
-+static const struct match_chip_info chip_info_2712 = {
-+      .init_func = &brcm_usb_dvr_init_2712,
-+      .required_regs = {
-+              BRCM_REGS_CTRL,
-+              BRCM_REGS_XHCI_EC,
-+              BRCM_REGS_XHCI_GBL,
-+              BRCM_REGS_USB_MDIO,
-+              -1,
-+      },
-+      .optional_reg = BRCM_REGS_BDC_EC,
-+};
-+
- static const struct match_chip_info chip_info_7445 = {
-       .init_func = &brcm_usb_dvr_init_7445,
-       .required_regs = {
-@@ -338,6 +350,10 @@ static const struct of_device_id brcm_us
-               .data = &chip_info_7211b0,
-       },
-       {
-+              .compatible = "brcm,bcm2712-usb-phy",
-+              .data = &chip_info_2712,
-+      },
-+      {
-               .compatible = "brcm,brcmstb-usb-phy",
-               .data = &chip_info_7445,
-       },
---- a/drivers/usb/dwc3/core.c
-+++ b/drivers/usb/dwc3/core.c
-@@ -1223,6 +1223,24 @@ static void dwc3_config_threshold(struct
-       }
- }
-+static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc)
-+{
-+      struct device *dev = dwc->dev;
-+      u32 cfg;
-+
-+      if (!dwc->axi_pipe_limit)
-+              return;
-+      if (dwc->axi_pipe_limit > 16) {
-+              dev_err(dev, "Invalid axi_pipe_limit property\n");
-+              return;
-+      }
-+      cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1);
-+      cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15);
-+      cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1);
-+
-+      dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg);
-+}
-+
- /**
-  * dwc3_core_init - Low-level initialization of DWC3 Core
-  * @dwc: Pointer to our controller context structure
-@@ -1288,6 +1306,8 @@ static int dwc3_core_init(struct dwc3 *d
-       dwc3_set_incr_burst_type(dwc);
-+      dwc3_set_axi_pipe_limit(dwc);
-+
-       ret = dwc3_phy_power_on(dwc);
-       if (ret)
-               goto err_exit_phy;
-@@ -1377,6 +1397,24 @@ static int dwc3_core_init(struct dwc3 *d
-       dwc3_config_threshold(dwc);
-+      if (DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
-+              u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
-+              u8 tx_maxburst = dwc->tx_max_burst_prd;
-+
-+              if (tx_thr_num && tx_maxburst) {
-+                      reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
-+                      reg |= DWC3_GTXTHRCFG_PKTCNTSEL;
-+
-+                      reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0);
-+                      reg |= DWC3_GTXTHRCFG_TXPKTCNT(tx_thr_num);
-+
-+                      reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0);
-+                      reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
-+
-+                      dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
-+              }
-+      }
-+
-       return 0;
- err_power_off_phy:
-@@ -1520,6 +1558,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;
-+      u8                      axi_pipe_limit;
-       /* default to highest possible threshold */
-       lpm_nyet_threshold = 0xf;
-@@ -1540,6 +1579,9 @@ static void dwc3_get_properties(struct d
-        */
-       tx_fifo_resize_max_num = 6;
-+      /* Default to 0 (don't override hardware defaults) */
-+      axi_pipe_limit = 0;
-+
-       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
-       dwc->dis_split_quirk = device_property_read_bool(dev,
-                               "snps,dis-split-quirk");
-+      device_property_read_u8(dev, "snps,axi-pipe-limit",
-+                                 &axi_pipe_limit);
-+
-       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
-       dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
-       dwc->tx_max_burst_prd = tx_max_burst_prd;
-+      dwc->axi_pipe_limit = axi_pipe_limit;
-+
-       dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
- }
-@@ -1963,6 +2010,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");
-+      if (!dwc->sysdev_is_parent) {
-+              ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
-+              if (ret)
-+                      return ret;
-+      }
-+
-       dwc->reset = devm_reset_control_array_get_optional_shared(dev);
-       if (IS_ERR(dwc->reset)) {
-               ret = PTR_ERR(dwc->reset);
---- a/drivers/usb/dwc3/core.h
-+++ b/drivers/usb/dwc3/core.h
-@@ -185,6 +185,9 @@
- #define DWC3_GSBUSCFG0_INCRBRSTENA    (1 << 0) /* undefined length enable */
- #define DWC3_GSBUSCFG0_INCRBRST_MASK  0xff
-+/* Global SoC Bus Configuration Register 1 */
-+#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n)      (((n) & 0xf) << 8)
-+
- /* 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 {
-  * @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
-+ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers
-  * @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 {
-       u8                      tx_max_burst_prd;
-       u8                      tx_fifo_resize_max_num;
-       u8                      clear_stall_protocol;
-+      u8                      axi_pipe_limit;
-       const char              *hsphy_interface;
---- a/drivers/usb/dwc3/host.c
-+++ b/drivers/usb/dwc3/host.c
-@@ -82,16 +82,23 @@ out:
- int dwc3_host_init(struct dwc3 *dwc)
- {
-+      struct platform_device  *pdev = to_platform_device(dwc->dev);
-       struct property_entry   props[5];
-       struct platform_device  *xhci;
-       int                     ret, irq;
-       int                     prop_idx = 0;
-+      int                     id;
-       irq = dwc3_host_get_irq(dwc);
-       if (irq < 0)
-               return irq;
--      xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
-+      id = of_alias_get_id(pdev->dev.of_node, "usb");
-+      if (id >= 0)
-+              xhci = platform_device_alloc("xhci-hcd", id);
-+      else
-+              xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
-+
-       if (!xhci) {
-               dev_err(dwc->dev, "couldn't allocate xHCI device\n");
-               return -ENOMEM;
index 47fa0b75416cf171d4346101213f6f3eab8861cf..77aebef467c2eeb088254c4041ff4c09a7e8043e 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
 
 --- 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 <jonathan@raspberrypi.com>
                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 <jonathan@raspberrypi.com>
  
 --- 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 <jonathan@raspberrypi.com>
  #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 <jonathan@raspberrypi.com>
   * @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;
index 5b700990b2783a3d10ee6efc773606a9e691f1e0..db0cce8d59d1dd8190aeb563067c82d3055a656d 100644 (file)
@@ -22,7 +22,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
 
 --- 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 <jonathan@raspberrypi.com>
                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 <jonathan@raspberrypi.com>
        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 <jonathan@raspberrypi.com>
  #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 <jonathan@raspberrypi.com>
   * @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 (file)
index 0000000..521b340
--- /dev/null
@@ -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,<param>=<val>
+ 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,<param>=<val>
++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 (file)
index 0000000..818f95f
--- /dev/null
@@ -0,0 +1,71 @@
+From b3dd7e8947cddec41864e8d3ce5f5d8b81033d6a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Alexander Stein <alexander.stein@ew.tq-group.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+---
+ 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 (file)
index 0000000..7cf477c
--- /dev/null
@@ -0,0 +1,31 @@
+From f4f17c3fe223b3d8ad65f5420abbcd69ef901186 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+---
+ 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 (file)
index 0000000..027f457
--- /dev/null
@@ -0,0 +1,116 @@
+From 23037697914a6d1220768a752c6358d35ca03737 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+---
+ 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 (file)
index 0000000..219cfce
--- /dev/null
@@ -0,0 +1,60 @@
+From c633c2e93e460925120e0817c14bbfc444a70226 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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 <linux/gpio/consumer.h>
+ #include <linux/i2c.h>
+ #include <linux/module.h>
++#include <linux/moduleparam.h>
+ #include <linux/of.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/regmap.h>
+@@ -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 (file)
index 0000000..8e89479
--- /dev/null
@@ -0,0 +1,47 @@
+From eec7048c4e3aec1aadc21fcffcf6be9f5385f72a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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 (file)
index 0000000..0b04bf0
--- /dev/null
@@ -0,0 +1,327 @@
+From 0a0814f830829b1a377273ddb09c156c84e1a8ca Mon Sep 17 00:00:00 2001
+From: Alexander Stein <alexander.stein@ew.tq-group.com>
+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 <alexander.stein@ew.tq-group.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+---
+ 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 (file)
index 0000000..139cd58
--- /dev/null
@@ -0,0 +1,214 @@
+From 384e58f63a3a328f7f656052b6357f3408aac6c3 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 31 Dec 2024 20:33:46 +0000
+Subject: [PATCH] dtoverlays: Add overlay for Sony IMX415 image sensor
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ 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,<param>
++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 <dt-bindings/gpio/gpio.h>
++
++/{
++      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>,
++                     <&reg_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 (file)
index 0000000..aee483b
--- /dev/null
@@ -0,0 +1,146 @@
+From 4e8d73ce89c6dd6fdcb8dd7df8310762707c5b1a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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 (file)
index 0000000..7ad9e11
--- /dev/null
@@ -0,0 +1,231 @@
+From 6722e1358768671c1e5761aa092efb4ae62b2c46 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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 (file)
index 0000000..d037505
--- /dev/null
@@ -0,0 +1,136 @@
+From 0292614f8cd061f71f975dae7d74fe5324545321 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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 (file)
index 0000000..a184b31
--- /dev/null
@@ -0,0 +1,60 @@
+From 87fc066350358ce45f5ad52424c8a2e351b1720c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ };
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 (file)
index 0000000..520d1d6
--- /dev/null
@@ -0,0 +1,43 @@
+From 602be52637ecca0b247cf832c8a4ec345844d325 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..9363036
--- /dev/null
@@ -0,0 +1,70 @@
+From 7a4972f36a63eba4d862115265a7bf77ac1e4129 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..02857ce
--- /dev/null
@@ -0,0 +1,25 @@
+From 4f7341263ebd6ab2ae805c8f27191d24abc05a62 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..f080834
--- /dev/null
@@ -0,0 +1,58 @@
+From 4111f4ede92b1f5bf869f87c66fc39151999c42f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..bb5c21d
--- /dev/null
@@ -0,0 +1,53 @@
+From 62c33972e3eb724d80179fb71b05e923920f0b0d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..c95c1d4
--- /dev/null
@@ -0,0 +1,90 @@
+From 301420a8cc44ee457670e015adc3a08cfc4531a9 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+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 <jonathan@raspberrypi.com>
+---
+ 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 (file)
index 0000000..e514870
--- /dev/null
@@ -0,0 +1,57 @@
+From d70a60eb03ae4fc687b91b5f6c4684000be21c5f Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+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 <jonathan@raspberrypi.com>
+---
+ 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 (file)
index 0000000..0dd1ffa
--- /dev/null
@@ -0,0 +1,41 @@
+From eb4d8ffb2b007963662be7eca88baf0e5c358bd6 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+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 <jonathan@raspberrypi.com>
+---
+ 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 (file)
index 0000000..2139eef
--- /dev/null
@@ -0,0 +1,94 @@
+From e72f42ebc9a236c023f8027a37c9351d58e28b05 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.com>
+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 <jonathan@raspberrypi.com>
+---
+ 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 (file)
index 0000000..0aca41f
--- /dev/null
@@ -0,0 +1,38 @@
+From e56aa0bd2b552daa4349a7eb2e6b0dec81d3e5cc Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..71a64da
--- /dev/null
@@ -0,0 +1,84 @@
+From dafde0ac8b6d4b21578a677c8afad8714af47aaf Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..81b37af
--- /dev/null
@@ -0,0 +1,44 @@
+From d06cb3534b6553a1f76bef2ddaf833e23dc12a4c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+                                         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)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+                                         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 (file)
index 0000000..08a58f2
--- /dev/null
@@ -0,0 +1,29 @@
+From dfff38316c1284c30c68d02cc424bad0562cf253 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+[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 (file)
index 0000000..554c930
--- /dev/null
@@ -0,0 +1,31 @@
+From a73ecafc5532e31b184220149cc2863f625700bf Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+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 <naush@raspberrypi.com>
+---
+ .../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 (file)
index 0000000..51b8f7e
--- /dev/null
@@ -0,0 +1,82 @@
+From a452251cc286f2799969f047698c76fe3d7862b9 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+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 <naush@raspberrypi.com>
+---
+ .../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 (file)
index 0000000..227ada4
--- /dev/null
@@ -0,0 +1,163 @@
+From 5b958efc20d381ee103103df5df0c88dc02ada18 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <peyton.howe@bellsouth.net>
+Signed-off-by: Peyton Howe <peyton.howe@bellsouth.net>
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ 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 (file)
index 0000000..2872f18
--- /dev/null
@@ -0,0 +1,55 @@
+From e3297f3fbffdaec8076c00167261f504bb2c64b6 Mon Sep 17 00:00:00 2001
+From: Peyton Howe <peyton.howe@bellsouth.net>
+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 <peyton.howe@bellsouth.net>
+---
+ 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 (file)
index 0000000..6153498
--- /dev/null
@@ -0,0 +1,40 @@
+From 11381ac246576bc84dfc28f6cdd8030305c605aa Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ .../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 (file)
index 0000000..4892c27
--- /dev/null
@@ -0,0 +1,325 @@
+From ba9883e3b667e4f1fbeacc4346f6e9179a3a5479 Mon Sep 17 00:00:00 2001
+From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
+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 <nick.hollinghurst@raspberrypi.com>
+---
+ 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 (file)
index 0000000..cc0f31d
--- /dev/null
@@ -0,0 +1,102 @@
+From 94de19285cc9bd781394bf1aa4fb8d401aac5195 Mon Sep 17 00:00:00 2001
+From: James Sarrett <jsarrett@gmail.com>
+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 (file)
index 0000000..575d522
--- /dev/null
@@ -0,0 +1,57 @@
+From aabe16b3cdc6172618803ed7a6002d1099d306e5 Mon Sep 17 00:00:00 2001
+From: James Sarrett <jsarrett@gmail.com>
+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 (file)
index 0000000..72d7308
--- /dev/null
@@ -0,0 +1,2137 @@
+From a18d9ced4965462cb7b3b4252ada440395105308 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+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 <naush@raspberrypi.com>
+---
+ .../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 <linux/types.h>
+-#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, &reg_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, &reg_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 <linux/firmware.h>
+-#define BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK (0x04000000)
+-#define BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION (0x02000000)
+-#define BCS_ISTATUS_HOST_DRIVER_DOWN         (0x08000000)
+-#define BCS_ISTATUS_SOC_CONNECT_ACCEPTED     (0x10000000)
+-#define BCS_ISTATUS_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 <linux/kconfig.h>
+ #include <linux/printk.h>
+-
+-#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 <linux/pagemap.h>
+ #include <linux/firmware.h>
+ #include <linux/kthread.h>
++#include <linux/delay.h>
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
+ #include <linux/dma-direct.h>
+@@ -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 <linux/pci-aspm.h>
+@@ -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 <linux/ioctl.h>
++#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 <linux/uaccess.h>
+-#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(&params, (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 <linux/sched.h>
+ #include <linux/module.h>
+-
+-#define SGL_MAX_SEGMENT_SIZE  (0x10000)
+ // See linux/mm.h
+ #define MMIO_AND_NO_PAGES_VMA_MASK (VM_IO | VM_PFNMAP)
++// 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 (file)
index 0000000..c763b1d
--- /dev/null
@@ -0,0 +1,139 @@
+From fa71765fd3c98fa170407e72e052004913da6874 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..504e463
--- /dev/null
@@ -0,0 +1,1630 @@
+From a320d39840745502d420f56b3d49b3723a12058f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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,<param>[=<val>
+ 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: <None>
+-Name:   i2c-fan
+-Info:   Adds support for a number of I2C fan controllers
+-Load:   dtoverlay=i2c-fan,<param>=<val>
+-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:   <Documentation>
++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,<param>=<val>
++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,<param>=<val>
+ 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,<param>=<val>
+ 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,<param>=<val>
+ 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,<param>=<val>
+ 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,<param>=<val>
+ 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 <dt-bindings/thermal/thermal.h>
++#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 <dt-bindings/mux/mux.h>
++#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=", <MUX_IDLE_DISCONNECT>,
+                       <&pca9545>,"idle-state:0=", <MUX_IDLE_DISCONNECT>,
+--- 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 = <&reg_display>;
++      reset-gpio = <&reg_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 = <&reg_display>;
+-                      reset-gpio = <&reg_display 1 1>;
+-              };
+-      };
+       __overrides__ {
+               dsi0 = <&dsi_frag>, "target:0=",<&dsi0>,
+                      <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+-                     <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+                      <&panel_disp>, "reg:0=0",
+                      <&reg_bridge>, "reg:0=0",
+                      <&reg_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 = <&reg_display>;
++      reset-gpio = <&reg_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 = <&reg_display>;
+-                      reset-gpio = <&reg_display 1 1>;
+-              };
+-      };
+       __overrides__ {
+               dsi0 = <&dsi_frag>, "target:0=",<&dsi0>,
+                      <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+-                     <&ts_i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+                      <&reg_bridge>, "reg:0=0",
+                      <&reg_bridge>, "regulator-name=bridge_reg_0";
+               disable_touch = <&ft5406>, "status=disabled";
diff --git a/target/linux/bcm27xx/patches-6.6/950-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 (file)
index 0000000..a084ec6
--- /dev/null
@@ -0,0 +1,63 @@
+From 8a08b4ad6dbd48a826b3052e52a4fdc88c3ac36e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..fa32b71
--- /dev/null
@@ -0,0 +1,29 @@
+From 54a442deb925c37346abbbcc566234757925910c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..2fa70f3
--- /dev/null
@@ -0,0 +1,42 @@
+From e0a21a407b78477aa530800255d53405950cb1fb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..cf0bbc8
--- /dev/null
@@ -0,0 +1,103 @@
+From 3f60adc5ce8238996ec43d2b76a6e38e46f8271b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..5d6014d
--- /dev/null
@@ -0,0 +1,30 @@
+From 4d577c42b47dfffda80da995fafd5b16fdb242e2 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..9ac62a3
--- /dev/null
@@ -0,0 +1,25 @@
+From fab0093d88452972f05f4b13e91e31d00b55421a Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..a742b30
--- /dev/null
@@ -0,0 +1,76 @@
+From 2cdd83392ba025cc88072c0153d443fc59919960 Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+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 <joerg@hifiberry.com>
+---
+ 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: <None>
+ 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: <None>
+--- 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 <dt-bindings/gpio/gpio.h>
++
+ / {
+       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 (file)
index 0000000..fec52cc
--- /dev/null
@@ -0,0 +1,75 @@
+From d664f45f77423b03e5a435e480822075c03331bd Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@hifiberry.com>
+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 <joerg@hifiberry.com>
+---
+ 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-1539-Reapply-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
new file mode 100644 (file)
index 0000000..327819f
--- /dev/null
@@ -0,0 +1,337 @@
+From 1b1e75ae7d69816609a95ff2fb92729a2ff04d8e Mon Sep 17 00:00:00 2001
+From: Dom Cobley <popcornmix@gmail.com>
+Date: Mon, 10 Feb 2025 13:26:33 +0000
+Subject: [PATCH] Reapply "usb: dwc3: Set DMA and coherent masks early"
+
+This reverts commit 09dfdf6129532e19b2cfd4992d1d09e7119ccd48.
+---
+ drivers/phy/broadcom/Kconfig                  |  2 +-
+ .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++
+ drivers/phy/broadcom/phy-brcm-usb-init.h      |  2 +
+ drivers/phy/broadcom/phy-brcm-usb.c           | 18 +++++-
+ drivers/usb/dwc3/core.c                       | 53 +++++++++++++++++
+ drivers/usb/dwc3/core.h                       |  5 ++
+ drivers/usb/dwc3/host.c                       |  9 ++-
+ 7 files changed, 145 insertions(+), 3 deletions(-)
+
+--- a/drivers/phy/broadcom/Kconfig
++++ b/drivers/phy/broadcom/Kconfig
+@@ -93,7 +93,7 @@ config PHY_BRCM_SATA
+ config PHY_BRCM_USB
+       tristate "Broadcom STB USB PHY driver"
+-      depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST
++      depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
+       depends on OF
+       select GENERIC_PHY
+       select SOC_BRCMSTB if ARCH_BRCMSTB
+--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
++++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
+@@ -341,6 +341,36 @@ static void usb_init_common_7216(struct
+       usb_init_common(params);
+ }
++static void usb_init_common_2712(struct brcm_usb_init_params *params)
++{
++      void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
++      void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
++      u32 reg;
++
++      if (params->syscon_piarbctl)
++              syscon_piarbctl_init(params->syscon_piarbctl);
++
++      USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
++
++      usb_wake_enable_7211b0(params, false);
++
++      usb_init_common(params);
++
++      /*
++       * The BDC controller will get occasional failures with
++       * the default "Read Transaction Size" of 6 (1024 bytes).
++       * Set it to 4 (256 bytes).
++       */
++      if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) {
++              reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
++              reg &= ~BDC_EC_AXIRDA_RTS_MASK;
++              reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
++              brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
++      }
++
++      usb2_eye_fix_7211b0(params);
++}
++
+ static void usb_init_xhci(struct brcm_usb_init_params *params)
+ {
+       pr_debug("%s\n", __func__);
+@@ -386,6 +416,18 @@ static void usb_uninit_common_7211b0(str
+ }
++static void usb_uninit_common_2712(struct brcm_usb_init_params *params)
++{
++      void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
++
++      if (params->wake_enabled) {
++              USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
++              usb_wake_enable_7211b0(params, true);
++      } else {
++              USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
++      }
++}
++
+ static void usb_uninit_xhci(struct brcm_usb_init_params *params)
+ {
+@@ -440,6 +482,16 @@ static const struct brcm_usb_init_ops bc
+       .set_dual_select = usb_set_dual_select,
+ };
++static const struct brcm_usb_init_ops bcm2712_ops = {
++      .init_ipp = usb_init_ipp,
++      .init_common = usb_init_common_2712,
++      .init_xhci = usb_init_xhci,
++      .uninit_common = usb_uninit_common_2712,
++      .uninit_xhci = usb_uninit_xhci,
++      .get_dual_select = usb_get_dual_select,
++      .set_dual_select = usb_set_dual_select,
++};
++
+ void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
+ {
+@@ -457,3 +509,10 @@ void brcm_usb_dvr_init_7211b0(struct brc
+       params->family_name = "7211";
+       params->ops = &bcm7211b0_ops;
+ }
++
++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params)
++{
++      params->family_name = "2712";
++      params->ops = &bcm2712_ops;
++      params->suspend_with_clocks = true;
++}
+--- a/drivers/phy/broadcom/phy-brcm-usb-init.h
++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h
+@@ -70,12 +70,14 @@ struct  brcm_usb_init_params {
+       const struct brcm_usb_init_ops *ops;
+       struct regmap *syscon_piarbctl;
+       bool wake_enabled;
++      bool suspend_with_clocks;
+ };
+ void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
+ void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
+ void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
+ void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params);
++void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params);
+ static inline u32 brcm_usb_readl(void __iomem *addr)
+ {
+--- a/drivers/phy/broadcom/phy-brcm-usb.c
++++ b/drivers/phy/broadcom/phy-brcm-usb.c
+@@ -75,7 +75,7 @@ struct brcm_usb_phy_data {
+ };
+ static s8 *node_reg_names[BRCM_REGS_MAX] = {
+-      "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
++      "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
+ };
+ static int brcm_pm_notifier(struct notifier_block *notifier,
+@@ -315,6 +315,18 @@ static const struct match_chip_info chip
+       .optional_reg = BRCM_REGS_BDC_EC,
+ };
++static const struct match_chip_info chip_info_2712 = {
++      .init_func = &brcm_usb_dvr_init_2712,
++      .required_regs = {
++              BRCM_REGS_CTRL,
++              BRCM_REGS_XHCI_EC,
++              BRCM_REGS_XHCI_GBL,
++              BRCM_REGS_USB_MDIO,
++              -1,
++      },
++      .optional_reg = BRCM_REGS_BDC_EC,
++};
++
+ static const struct match_chip_info chip_info_7445 = {
+       .init_func = &brcm_usb_dvr_init_7445,
+       .required_regs = {
+@@ -338,6 +350,10 @@ static const struct of_device_id brcm_us
+               .data = &chip_info_7211b0,
+       },
+       {
++              .compatible = "brcm,bcm2712-usb-phy",
++              .data = &chip_info_2712,
++      },
++      {
+               .compatible = "brcm,brcmstb-usb-phy",
+               .data = &chip_info_7445,
+       },
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1223,6 +1223,24 @@ static void dwc3_config_threshold(struct
+       }
+ }
++static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc)
++{
++      struct device *dev = dwc->dev;
++      u32 cfg;
++
++      if (!dwc->axi_pipe_limit)
++              return;
++      if (dwc->axi_pipe_limit > 16) {
++              dev_err(dev, "Invalid axi_pipe_limit property\n");
++              return;
++      }
++      cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1);
++      cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15);
++      cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1);
++
++      dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg);
++}
++
+ /**
+  * dwc3_core_init - Low-level initialization of DWC3 Core
+  * @dwc: Pointer to our controller context structure
+@@ -1288,6 +1306,8 @@ static int dwc3_core_init(struct dwc3 *d
+       dwc3_set_incr_burst_type(dwc);
++      dwc3_set_axi_pipe_limit(dwc);
++
+       ret = dwc3_phy_power_on(dwc);
+       if (ret)
+               goto err_exit_phy;
+@@ -1386,6 +1406,24 @@ static int dwc3_core_init(struct dwc3 *d
+       dwc3_config_threshold(dwc);
++      if (DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
++              u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
++              u8 tx_maxburst = dwc->tx_max_burst_prd;
++
++              if (tx_thr_num && tx_maxburst) {
++                      reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
++                      reg |= DWC3_GTXTHRCFG_PKTCNTSEL;
++
++                      reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0);
++                      reg |= DWC3_GTXTHRCFG_TXPKTCNT(tx_thr_num);
++
++                      reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0);
++                      reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
++
++                      dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
++              }
++      }
++
+       return 0;
+ err_power_off_phy:
+@@ -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;
++      u8                      axi_pipe_limit;
+       /* default to highest possible threshold */
+       lpm_nyet_threshold = 0xf;
+@@ -1549,6 +1588,9 @@ static void dwc3_get_properties(struct d
+        */
+       tx_fifo_resize_max_num = 6;
++      /* Default to 0 (don't override hardware defaults) */
++      axi_pipe_limit = 0;
++
+       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);
+@@ -1669,6 +1711,9 @@ static void dwc3_get_properties(struct d
+       dwc->dis_split_quirk = device_property_read_bool(dev,
+                               "snps,dis-split-quirk");
++      device_property_read_u8(dev, "snps,axi-pipe-limit",
++                                 &axi_pipe_limit);
++
+       dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+       dwc->tx_de_emphasis = tx_de_emphasis;
+@@ -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;
++      dwc->axi_pipe_limit = axi_pipe_limit;
++
+       dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
+ }
+@@ -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");
++      if (!dwc->sysdev_is_parent) {
++              ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
++              if (ret)
++                      return ret;
++      }
++
+       dwc->reset = devm_reset_control_array_get_optional_shared(dev);
+       if (IS_ERR(dwc->reset)) {
+               ret = PTR_ERR(dwc->reset);
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -185,6 +185,9 @@
+ #define DWC3_GSBUSCFG0_INCRBRSTENA    (1 << 0) /* undefined length enable */
+ #define DWC3_GSBUSCFG0_INCRBRST_MASK  0xff
++/* Global SoC Bus Configuration Register 1 */
++#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n)      (((n) & 0xf) << 8)
++
+ /* Global Debug LSP MUX Select */
+ #define DWC3_GDBGLSPMUX_ENDBC         BIT(15) /* Host only */
+ #define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
+@@ -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
++ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers
+  * @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
+@@ -1311,6 +1315,7 @@ struct dwc3 {
+       u8                      tx_max_burst_prd;
+       u8                      tx_fifo_resize_max_num;
+       u8                      clear_stall_protocol;
++      u8                      axi_pipe_limit;
+       const char              *hsphy_interface;
+--- a/drivers/usb/dwc3/host.c
++++ b/drivers/usb/dwc3/host.c
+@@ -82,16 +82,23 @@ out:
+ int dwc3_host_init(struct dwc3 *dwc)
+ {
++      struct platform_device  *pdev = to_platform_device(dwc->dev);
+       struct property_entry   props[5];
+       struct platform_device  *xhci;
+       int                     ret, irq;
+       int                     prop_idx = 0;
++      int                     id;
+       irq = dwc3_host_get_irq(dwc);
+       if (irq < 0)
+               return irq;
+-      xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
++      id = of_alias_get_id(pdev->dev.of_node, "usb");
++      if (id >= 0)
++              xhci = platform_device_alloc("xhci-hcd", id);
++      else
++              xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
++
+       if (!xhci) {
+               dev_err(dwc->dev, "couldn't allocate xHCI device\n");
+               return -ENOMEM;
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 (file)
index 0000000..f16d0bd
--- /dev/null
@@ -0,0 +1,119 @@
+From 081eebdeccfd12e0aaba4b64c9f87b608777913b Mon Sep 17 00:00:00 2001
+From: Micke Prag <micke.prag@gmail.com>
+Date: Thu, 13 Feb 2025 22:08:43 +0100
+Subject: [PATCH] overlays: Add OpenHydroponics RootMaster overlay
+
+Signed-off-by: Micke Prag <micke.prag@gmail.com>
+---
+ 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: <None>
++
++
+ Name:   rotary-encoder
+ Info:   Overlay for GPIO connected rotary encoder.
+ Load:   dtoverlay=rotary-encoder,<param>=<val>
+--- /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 <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/bcm2835.h>
++
++/ {
++      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 = <BCM2835_FSEL_GPIO_IN>;
++                      };
++              };
++      };
++      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 (file)
index 0000000..784ae52
--- /dev/null
@@ -0,0 +1,37 @@
+From 011cbf22d7583687ae18690185169e5da0be000a Mon Sep 17 00:00:00 2001
+From: Yuriy Pasichnyk <yurijpasichnyk11@gmail.com>
+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 <yurijpasichnyk11@gmail.com>
+---
+ 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 (file)
index 0000000..af9c9f9
--- /dev/null
@@ -0,0 +1,32 @@
+From af9965a855a8c6c7140bbcccfa89eec7e90a993d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ 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 (file)
index 0000000..98eaf56
--- /dev/null
@@ -0,0 +1,38 @@
+From a4e7897eef1ad4628572a6abfd30291209a0bf43 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+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 <richard.oliver@raspberrypi.com>
+---
+ 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 (file)
index 0000000..31e35a3
--- /dev/null
@@ -0,0 +1,25 @@
+From f8f3e202fb083906fbc98ef6ea445e424779c076 Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+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 <richard.oliver@raspberrypi.com>
+---
+ 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 (file)
index 0000000..04b9ea6
--- /dev/null
@@ -0,0 +1,37 @@
+From 2e071057fded90e789c0101498e45a1778be93fe Mon Sep 17 00:00:00 2001
+From: Richard Oliver <richard.oliver@raspberrypi.com>
+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 <richard.oliver@raspberrypi.com>
+---
+ 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 (file)
index 0000000..13fa24b
--- /dev/null
@@ -0,0 +1,30 @@
+From 1337c39626c14ca5e61b4cddbc097d87212a0b13 Mon Sep 17 00:00:00 2001
+From: KubaTaba1uga <luna7337anul@proton.me>
+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 (file)
index 0000000..0918f8c
--- /dev/null
@@ -0,0 +1,22 @@
+From f1076a9d7a269d72b6707283560d0d38203cb07a Mon Sep 17 00:00:00 2001
+From: KubaTaba1uga <luna7337anul@proton.me>
+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 (file)
index 0000000..a2b7df7
--- /dev/null
@@ -0,0 +1,66 @@
+From ac56a225e0889e60e912ecd3a51333a5aee901fc Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+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 <dave.stevenson@raspberrypi.com>
+---
+ 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>,
+                      <&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 (file)
index 0000000..3bce057
--- /dev/null
@@ -0,0 +1,129 @@
+From 32c319ba2f2fd662a3b7bd042515cd650807dbff Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+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 <wahrenst@gmx.net>
+Reviewed-by: Maíra Canal <mcanal@igalia.com>
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..cdb9ad1
--- /dev/null
@@ -0,0 +1,61 @@
+From 5258ca4ad089548a72657522443b9c3e46fd125b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..3bf33ff
--- /dev/null
@@ -0,0 +1,84 @@
+From 131564261399a36a5cf2ac2731ed1ceffba93d10 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..a13516a
--- /dev/null
@@ -0,0 +1,447 @@
+From 97988373018e7fa7ff33b7774f88d30e48f71509 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 <linux/dma-mapping.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/of.h>
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
+ #include <linux/reset.h>
+@@ -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 (file)
index 0000000..fb03d82
--- /dev/null
@@ -0,0 +1,43 @@
+From 08e99bc475ad907f3087e4f14c2ddb6560514da1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <krzk+dt@kernel.org>
+Cc: Conor Dooley <conor+dt@kernel.org>
+Cc: Nicolas Saenz Julienne <nsaenz@kernel.org>
+Cc: devicetree@vger.kernel.org
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..a39e724
--- /dev/null
@@ -0,0 +1,198 @@
+From 85e1a7592aa192d760159f9bc6e83d56fdf433f3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..2d43d1c
--- /dev/null
@@ -0,0 +1,27 @@
+From 3c21211667e35029054b0dfebdf292e4e7d5754b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
+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 <mcanal@igalia.com>
+---
+ 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 (file)
index 0000000..faccc79
--- /dev/null
@@ -0,0 +1,21 @@
+From 08d4e8f52256bd422d8a1f876411603f627d0a82 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+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 <phil@raspberrypi.com>
+---
+ arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
+@@ -7,7 +7,7 @@
+ };
+ &pwr_key {
+-      debounce-interval = <400>;
++      debounce-interval = <0>;
+ };
+ &gio {