]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
bcm27xx: sync 5.4 patches with RPi Foundation
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Mon, 16 Mar 2020 19:41:03 +0000 (20:41 +0100)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Mon, 16 Mar 2020 20:24:23 +0000 (21:24 +0100)
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
288 files changed:
target/linux/bcm27xx/bcm2708/config-5.4
target/linux/bcm27xx/bcm2709/config-5.4
target/linux/bcm27xx/bcm2710/config-5.4
target/linux/bcm27xx/bcm2711/config-5.4
target/linux/bcm27xx/patches-5.4/950-0205-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0205-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch [moved from target/linux/bcm27xx/patches-5.4/950-0208-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0206-PCI-brcmstb-Add-dma-range-mapping-for-inbound-traffi.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0206-arm-bcm2835-DMA-can-only-address-1GB.patch [moved from target/linux/bcm27xx/patches-5.4/950-0210-arm-bcm2835-DMA-can-only-address-1GB.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0207-PCI-brcmstb-Add-MSI-capability.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0207-hwrng-iproc-rng200-Add-BCM2838-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0211-hwrng-iproc-rng200-Add-BCM2838-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0208-thermal-brcmstb_thermal-Add-BCM2838-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0212-thermal-brcmstb_thermal-Add-BCM2838-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0209-pcie-brcmstb-Changes-for-BCM2711.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0209-vchiq-Add-36-bit-address-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0213-vchiq-Add-36-bit-address-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0210-bcm2835-pcm.c-Support-multichannel-audio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0214-bcm2835-pcm.c-Support-multichannel-audio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0211-bcmgenet-constrain-max-DMA-burst-length.patch [moved from target/linux/bcm27xx/patches-5.4/950-0215-bcmgenet-constrain-max-DMA-burst-length.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0212-bcmgenet-Better-coalescing-parameter-defaults.patch [moved from target/linux/bcm27xx/patches-5.4/950-0216-bcmgenet-Better-coalescing-parameter-defaults.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0213-net-genet-enable-link-energy-detect-powerdown-for-ex.patch [moved from target/linux/bcm27xx/patches-5.4/950-0217-net-genet-enable-link-energy-detect-powerdown-for-ex.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0214-usb-xhci-Disable-the-XHCI-5-second-timeout.patch [moved from target/linux/bcm27xx/patches-5.4/950-0218-usb-xhci-Disable-the-XHCI-5-second-timeout.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0215-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch [moved from target/linux/bcm27xx/patches-5.4/950-0219-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0216-spi-bcm2835-enable-shared-interrupt-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0220-spi-bcm2835-enable-shared-interrupt-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0217-clk-bcm2835-Don-t-wait-for-pllh-lock.patch [moved from target/linux/bcm27xx/patches-5.4/950-0221-clk-bcm2835-Don-t-wait-for-pllh-lock.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0218-soc-bcm-bcm2835-pm-Add-support-for-2711.patch [moved from target/linux/bcm27xx/patches-5.4/950-0222-soc-bcm-bcm2835-pm-Add-support-for-2711.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0219-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch [moved from target/linux/bcm27xx/patches-5.4/950-0223-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch with 66% similarity]
target/linux/bcm27xx/patches-5.4/950-0220-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch [moved from target/linux/bcm27xx/patches-5.4/950-0224-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0221-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch [moved from target/linux/bcm27xx/patches-5.4/950-0225-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0222-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch [moved from target/linux/bcm27xx/patches-5.4/950-0226-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0223-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch [moved from target/linux/bcm27xx/patches-5.4/950-0227-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0224-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch [moved from target/linux/bcm27xx/patches-5.4/950-0228-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0225-arm-bcm2835-Add-bcm2838-compatible-string.patch [moved from target/linux/bcm27xx/patches-5.4/950-0229-arm-bcm2835-Add-bcm2838-compatible-string.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0226-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch [moved from target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0227-drm-v3d-Add-support-for-2711.patch [moved from target/linux/bcm27xx/patches-5.4/950-0231-drm-v3d-Add-support-for-2711.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0228-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch [moved from target/linux/bcm27xx/patches-5.4/950-0232-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0229-drm-v3d-Hook-up-the-runtime-PM-ops.patch [moved from target/linux/bcm27xx/patches-5.4/950-0233-drm-v3d-Hook-up-the-runtime-PM-ops.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch [moved from target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0232-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0233-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch [moved from target/linux/bcm27xx/patches-5.4/950-0237-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Increase-max-screen-size-to-4096x4096.patch [moved from target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Increase-max-screen-size-to-4096x4096.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Fix-build-warning.patch [moved from target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Fix-build-warning.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Select-display-to-blank-during-initialisatio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Select-display-to-blank-during-initialisatio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Remove-now-unused-structure.patch [moved from target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Remove-now-unused-structure.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch [moved from target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Set-the-display-number-when-querying-the-dis.patch [moved from target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-Set-the-display-number-when-querying-the-dis.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch [moved from target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch [moved from target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch [moved from target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-Increase-max_width-height-to-7680.patch [moved from target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Increase-max_width-height-to-7680.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch [moved from target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch [moved from target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-Log-flags-in-fkms-mode-set.patch [moved from target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Log-flags-in-fkms-mode-set.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-firmware-kms-Fix-DSI-display-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-firmware-kms-Fix-DSI-display-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch [moved from target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-handle-the-case-where-there-are-no-available.patch [moved from target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-handle-the-case-where-there-are-no-available.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Support-the-VEC-in-FKMS.patch [moved from target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-Support-the-VEC-in-FKMS.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-Correct-SAND-support-for-FKMS.patch [moved from target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Correct-SAND-support-for-FKMS.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch [moved from target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch [moved from target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch [moved from target/linux/bcm27xx/patches-5.4/950-0263-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch [moved from target/linux/bcm27xx/patches-5.4/950-0264-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4-Add-status-of-which-display-is-updated-throu.patch [moved from target/linux/bcm27xx/patches-5.4/950-0265-drm-vc4-Add-status-of-which-display-is-updated-throu.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0266-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0263-drm-vc4-Limit-fkms-to-modes-85Hz.patch [moved from target/linux/bcm27xx/patches-5.4/950-0267-drm-vc4-Limit-fkms-to-modes-85Hz.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0264-drm-vc4-Ignore-HVS-unless-initialised.patch [moved from target/linux/bcm27xx/patches-5.4/950-0268-drm-vc4-Ignore-HVS-unless-initialised.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0265-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch [moved from target/linux/bcm27xx/patches-5.4/950-0269-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0266-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch [moved from target/linux/bcm27xx/patches-5.4/950-0270-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0267-tty-amba-pl011-Make-TX-optimisation-conditional.patch [moved from target/linux/bcm27xx/patches-5.4/950-0271-tty-amba-pl011-Make-TX-optimisation-conditional.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0268-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch [moved from target/linux/bcm27xx/patches-5.4/950-0272-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0269-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0273-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0270-staging-vc04_services-fix-compiling-in-separate-dire.patch [moved from target/linux/bcm27xx/patches-5.4/950-0275-staging-vc04_services-fix-compiling-in-separate-dire.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0271-clk-bcm2835-Avoid-null-pointer-exception.patch [moved from target/linux/bcm27xx/patches-5.4/950-0277-clk-bcm2835-Avoid-null-pointer-exception.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0272-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch [moved from target/linux/bcm27xx/patches-5.4/950-0279-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0273-drm-v3d-HACK-gut-runtime-pm-for-now.patch [moved from target/linux/bcm27xx/patches-5.4/950-0280-drm-v3d-HACK-gut-runtime-pm-for-now.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0274-arm64-mm-Limit-the-DMA-zone-for-arm64.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0274-drm-v3d-Clock-V3D-down-when-not-in-use.patch [moved from target/linux/bcm27xx/patches-5.4/950-0281-drm-v3d-Clock-V3D-down-when-not-in-use.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0275-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch [moved from target/linux/bcm27xx/patches-5.4/950-0282-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0276-bcm2835-dma-Add-proper-40-bit-DMA-support.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0276-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch [moved from target/linux/bcm27xx/patches-5.4/950-0284-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch [moved from target/linux/bcm27xx/patches-5.4/950-0285-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0278-drm-vc4-Add-support-for-margins-to-fkms.patch [moved from target/linux/bcm27xx/patches-5.4/950-0286-drm-vc4-Add-support-for-margins-to-fkms.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0278-pcie-brcmstb-Don-t-set-DMA-ops-for-root-complex.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0279-drm-vc4-Ensure-zpos-is-always-initialised.patch [moved from target/linux/bcm27xx/patches-5.4/950-0287-drm-vc4-Ensure-zpos-is-always-initialised.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0280-adds-the-Hifiberry-DAC-ADC-PRO-version.patch [moved from target/linux/bcm27xx/patches-5.4/950-0288-adds-the-Hifiberry-DAC-ADC-PRO-version.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0281-drm-vc4-A-present-but-empty-dmas-disables-audio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0289-drm-vc4-A-present-but-empty-dmas-disables-audio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0282-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch [moved from target/linux/bcm27xx/patches-5.4/950-0290-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0283-Ported-pcie-brcmstb-bounce-buffer-implementation-to-.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0283-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch [moved from target/linux/bcm27xx/patches-5.4/950-0291-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0284-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch [moved from target/linux/bcm27xx/patches-5.4/950-0292-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0285-drm-vc4-Add-Broadcast-RGB-connector-property.patch [moved from target/linux/bcm27xx/patches-5.4/950-0293-drm-vc4-Add-Broadcast-RGB-connector-property.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0286-drm-vc4-fkms-Set-default-state-margin-at-reset.patch [moved from target/linux/bcm27xx/patches-5.4/950-0294-drm-vc4-fkms-Set-default-state-margin-at-reset.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0287-staging-bcm2835-codec-switch-to-multi-planar-API.patch [moved from target/linux/bcm27xx/patches-5.4/950-0295-staging-bcm2835-codec-switch-to-multi-planar-API.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0288-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch [moved from target/linux/bcm27xx/patches-5.4/950-0296-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0289-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch [moved from target/linux/bcm27xx/patches-5.4/950-0297-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0290-Add-HDMI1-facility-to-the-driver.patch [moved from target/linux/bcm27xx/patches-5.4/950-0298-Add-HDMI1-facility-to-the-driver.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch [moved from target/linux/bcm27xx/patches-5.4/950-0299-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0292-drm-vc4-Remove-unused-mode-variable.patch [moved from target/linux/bcm27xx/patches-5.4/950-0300-drm-vc4-Remove-unused-mode-variable.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0293-staging-bcm2835-codec-Expand-logging-on-format-setti.patch [moved from target/linux/bcm27xx/patches-5.4/950-0301-staging-bcm2835-codec-Expand-logging-on-format-setti.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0294-staging-bcm2835-codec-Correct-bytesperline-on-format.patch [moved from target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Correct-bytesperline-on-format.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0295-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch [moved from target/linux/bcm27xx/patches-5.4/950-0303-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0296-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch [moved from target/linux/bcm27xx/patches-5.4/950-0304-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0297-xhci-Use-more-event-ring-segment-table-entries.patch [moved from target/linux/bcm27xx/patches-5.4/950-0305-xhci-Use-more-event-ring-segment-table-entries.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0298-configs-arm64-bcm2711-Enable-V3D.patch [moved from target/linux/bcm27xx/patches-5.4/950-0306-configs-arm64-bcm2711-Enable-V3D.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch [moved from target/linux/bcm27xx/patches-5.4/950-0307-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0300-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0301-arch-arm-Add-model-string-to-cpuinfo.patch [moved from target/linux/bcm27xx/patches-5.4/950-0309-arch-arm-Add-model-string-to-cpuinfo.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0302-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch [moved from target/linux/bcm27xx/patches-5.4/950-0310-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-Fix-non-documentation-comment-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0313-staging-bcm2835-codec-Fix-non-documentation-comment-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0304-staging-bcm2835-codec-Fix-declaration-of-roles.patch [moved from target/linux/bcm27xx/patches-5.4/950-0314-staging-bcm2835-codec-Fix-declaration-of-roles.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-codec-Add-role-to-device-name.patch [moved from target/linux/bcm27xx/patches-5.4/950-0315-staging-bcm2835-codec-Add-role-to-device-name.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0306-staging-bcm2835-codec-Pass-driver-context-to-create-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0316-staging-bcm2835-codec-Pass-driver-context-to-create-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0307-staging-bcm2835-codec-add-media-controller-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0317-staging-bcm2835-codec-add-media-controller-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0308-v4l2-Add-a-Greyworld-AWB-mode.patch [moved from target/linux/bcm27xx/patches-5.4/950-0318-v4l2-Add-a-Greyworld-AWB-mode.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0309-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch [moved from target/linux/bcm27xx/patches-5.4/950-0319-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0310-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch [moved from target/linux/bcm27xx/patches-5.4/950-0320-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0311-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch [moved from target/linux/bcm27xx/patches-5.4/950-0321-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0311-media-dt-bindings-Add-binding-for-the-Sony-IMX219-se.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0312-staging-bcm2835-codec-Allow-height-of-1920.patch [moved from target/linux/bcm27xx/patches-5.4/950-0322-staging-bcm2835-codec-Allow-height-of-1920.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0313-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch [moved from target/linux/bcm27xx/patches-5.4/950-0323-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0314-drm-v3d-Delete-pm_runtime-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0324-drm-v3d-Delete-pm_runtime-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0315-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch [moved from target/linux/bcm27xx/patches-5.4/950-0325-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0316-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch [moved from target/linux/bcm27xx/patches-5.4/950-0326-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0317-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch [moved from target/linux/bcm27xx/patches-5.4/950-0327-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0318-dma-direct-Temporary-DMA-fix-on-arm64.patch [moved from target/linux/bcm27xx/patches-5.4/950-0328-dma-direct-Temporary-DMA-fix-on-arm64.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0319-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch [moved from target/linux/bcm27xx/patches-5.4/950-0329-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0320-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch [moved from target/linux/bcm27xx/patches-5.4/950-0330-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0321-vchiq_2835_arm-suppress-warning.patch [moved from target/linux/bcm27xx/patches-5.4/950-0331-vchiq_2835_arm-suppress-warning.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0322-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch [moved from target/linux/bcm27xx/patches-5.4/950-0332-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0323-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch [moved from target/linux/bcm27xx/patches-5.4/950-0334-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0324-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch [moved from target/linux/bcm27xx/patches-5.4/950-0335-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0325-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch [moved from target/linux/bcm27xx/patches-5.4/950-0336-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0326-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch [moved from target/linux/bcm27xx/patches-5.4/950-0337-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch with 99% similarity]
target/linux/bcm27xx/patches-5.4/950-0327-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch [moved from target/linux/bcm27xx/patches-5.4/950-0338-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0328-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch [moved from target/linux/bcm27xx/patches-5.4/950-0339-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0329-staging-bcm2835-codec-Set-default-and-error-check-ti.patch [moved from target/linux/bcm27xx/patches-5.4/950-0340-staging-bcm2835-codec-Set-default-and-error-check-ti.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0330-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch [moved from target/linux/bcm27xx/patches-5.4/950-0341-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0331-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch [moved from target/linux/bcm27xx/patches-5.4/950-0342-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0332-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0343-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0333-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch [moved from target/linux/bcm27xx/patches-5.4/950-0344-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0333-pcie-brcmstb-bounce64.c-dev_err-dev_info-for-info-me.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0334-drm-v3d-Suppress-all-but-the-first-MMU-error.patch [moved from target/linux/bcm27xx/patches-5.4/950-0345-drm-v3d-Suppress-all-but-the-first-MMU-error.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0335-drm-v3d-Plug-dma_fence-leak.patch [moved from target/linux/bcm27xx/patches-5.4/950-0346-drm-v3d-Plug-dma_fence-leak.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0336-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch [moved from target/linux/bcm27xx/patches-5.4/950-0347-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0337-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch [moved from target/linux/bcm27xx/patches-5.4/950-0348-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0338-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch [moved from target/linux/bcm27xx/patches-5.4/950-0349-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0339-staging-vchiq_arm-Unify-the-unload-handling-of-platf.patch [moved from target/linux/bcm27xx/patches-5.4/950-0350-staging-vchiq_arm-Unify-the-unload-handling-of-platf.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0340-net-bcmgenet-The-second-IRQ-is-optional.patch [moved from target/linux/bcm27xx/patches-5.4/950-0351-net-bcmgenet-The-second-IRQ-is-optional.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0341-drm-v3d-The-third-IRQ-is-optional.patch [moved from target/linux/bcm27xx/patches-5.4/950-0352-drm-v3d-The-third-IRQ-is-optional.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0342-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch [moved from target/linux/bcm27xx/patches-5.4/950-0353-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0343-rpi-poe-fan-fix-def_pwm1-writes.patch [moved from target/linux/bcm27xx/patches-5.4/950-0354-rpi-poe-fan-fix-def_pwm1-writes.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0344-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch [moved from target/linux/bcm27xx/patches-5.4/950-0355-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0345-overlays-smi-fix-typo-in-comment-3320.patch [moved from target/linux/bcm27xx/patches-5.4/950-0356-overlays-smi-fix-typo-in-comment-3320.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0346-net-phy-2711-Change-the-default-ethernet-LED-actions.patch [moved from target/linux/bcm27xx/patches-5.4/950-0357-net-phy-2711-Change-the-default-ethernet-LED-actions.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0347-overlays-Add-apds9960-overlay.patch [moved from target/linux/bcm27xx/patches-5.4/950-0358-overlays-Add-apds9960-overlay.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0348-overlays-Remove-hack-from-uart0-overlay.patch [moved from target/linux/bcm27xx/patches-5.4/950-0359-overlays-Remove-hack-from-uart0-overlay.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0349-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch [moved from target/linux/bcm27xx/patches-5.4/950-0360-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0350-v3d_drv-Handle-missing-clock-more-gracefully.patch [moved from target/linux/bcm27xx/patches-5.4/950-0361-v3d_drv-Handle-missing-clock-more-gracefully.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0351-v3d_drv-Allow-clock-retrieval-by-name.patch [moved from target/linux/bcm27xx/patches-5.4/950-0362-v3d_drv-Allow-clock-retrieval-by-name.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0352-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch [moved from target/linux/bcm27xx/patches-5.4/950-0363-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0353-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0364-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0354-clk-raspberrypi-Also-support-v3d-clock.patch [moved from target/linux/bcm27xx/patches-5.4/950-0365-clk-raspberrypi-Also-support-v3d-clock.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0355-clk-bcm2835-Disable-v3d-clock.patch [moved from target/linux/bcm27xx/patches-5.4/950-0366-clk-bcm2835-Disable-v3d-clock.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0356-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0367-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0357-arm-dts-Correct-Pi-4B-LED-values.patch [moved from target/linux/bcm27xx/patches-5.4/950-0368-arm-dts-Correct-Pi-4B-LED-values.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0358-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch [moved from target/linux/bcm27xx/patches-5.4/950-0369-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0359-arm-dts-2711-Add-pcie0-alias.patch [moved from target/linux/bcm27xx/patches-5.4/950-0370-arm-dts-2711-Add-pcie0-alias.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0360-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch [moved from target/linux/bcm27xx/patches-5.4/950-0371-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0361-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch [moved from target/linux/bcm27xx/patches-5.4/950-0372-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0362-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch [moved from target/linux/bcm27xx/patches-5.4/950-0373-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0363-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch [moved from target/linux/bcm27xx/patches-5.4/950-0374-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0364-overlays-Make-mcp342x-run-time-compatible.patch [moved from target/linux/bcm27xx/patches-5.4/950-0375-overlays-Make-mcp342x-run-time-compatible.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0365-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch [moved from target/linux/bcm27xx/patches-5.4/950-0376-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0366-sound-soc-only-first-codec-is-master-in-multicodec-s.patch [moved from target/linux/bcm27xx/patches-5.4/950-0377-sound-soc-only-first-codec-is-master-in-multicodec-s.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0367-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch [moved from target/linux/bcm27xx/patches-5.4/950-0378-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0368-overlays-dht11-Allow-multiple-instantiation.patch [moved from target/linux/bcm27xx/patches-5.4/950-0379-overlays-dht11-Allow-multiple-instantiation.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0369-overlays-i2c-rtc-Add-pcf85363-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0380-overlays-i2c-rtc-Add-pcf85363-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0370-pinctrl-bcm2835-Remove-gpiochip-on-error.patch [moved from target/linux/bcm27xx/patches-5.4/950-0381-pinctrl-bcm2835-Remove-gpiochip-on-error.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0371-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch [moved from target/linux/bcm27xx/patches-5.4/950-0382-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0372-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch [moved from target/linux/bcm27xx/patches-5.4/950-0383-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch [moved from target/linux/bcm27xx/patches-5.4/950-0385-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch [moved from target/linux/bcm27xx/patches-5.4/950-0386-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch [moved from target/linux/bcm27xx/patches-5.4/950-0387-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch [moved from target/linux/bcm27xx/patches-5.4/950-0388-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0377-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch [moved from target/linux/bcm27xx/patches-5.4/950-0389-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch [moved from target/linux/bcm27xx/patches-5.4/950-0390-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0379-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch [moved from target/linux/bcm27xx/patches-5.4/950-0391-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0380-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch [moved from target/linux/bcm27xx/patches-5.4/950-0392-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0381-net-bcmgenet-Add-RGMII_RXID-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0393-net-bcmgenet-Add-RGMII_RXID-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0382-ARM-dts-bcm2838-Backport-genet-from-upstream.patch [moved from target/linux/bcm27xx/patches-5.4/950-0394-ARM-dts-bcm2838-Backport-genet-from-upstream.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0383-ARM-bcm-Backport-BCM2711-support-from-upstream.patch [moved from target/linux/bcm27xx/patches-5.4/950-0395-ARM-bcm-Backport-BCM2711-support-from-upstream.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0384-hwrng-iproc-rng200-Add-support-for-BCM2711.patch [moved from target/linux/bcm27xx/patches-5.4/950-0396-hwrng-iproc-rng200-Add-support-for-BCM2711.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0384-pcie-brcmstb-Eliminate-arch_dma_ops-error-message.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0385-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch [moved from target/linux/bcm27xx/patches-5.4/950-0397-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch [moved from target/linux/bcm27xx/patches-5.4/950-0398-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch [moved from target/linux/bcm27xx/patches-5.4/950-0399-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0388-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0400-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0389-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch [moved from target/linux/bcm27xx/patches-5.4/950-0401-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0390-driver-char-rpimem-Add-SPDX-licence-header.patch [moved from target/linux/bcm27xx/patches-5.4/950-0402-driver-char-rpimem-Add-SPDX-licence-header.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0391-driver-char-rpivid-Fix-access-to-freed-memory.patch [moved from target/linux/bcm27xx/patches-5.4/950-0403-driver-char-rpivid-Fix-access-to-freed-memory.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0392-add-BME680-to-i2c-sensor-overlay.patch [moved from target/linux/bcm27xx/patches-5.4/950-0404-add-BME680-to-i2c-sensor-overlay.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0393-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch [moved from target/linux/bcm27xx/patches-5.4/950-0405-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0394-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch [moved from target/linux/bcm27xx/patches-5.4/950-0406-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0395-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch [moved from target/linux/bcm27xx/patches-5.4/950-0407-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0396-Add-universal-device-tree-overlay-for-SPI-devices.patch [moved from target/linux/bcm27xx/patches-5.4/950-0408-Add-universal-device-tree-overlay-for-SPI-devices.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0397-sound-Add-the-HiFiBerry-DAC-HD-version.patch [moved from target/linux/bcm27xx/patches-5.4/950-0409-sound-Add-the-HiFiBerry-DAC-HD-version.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0398-Initialise-rpi-firmware-before-clk-bcm2835.patch [moved from target/linux/bcm27xx/patches-5.4/950-0410-Initialise-rpi-firmware-before-clk-bcm2835.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0399-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch [moved from target/linux/bcm27xx/patches-5.4/950-0411-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0400-overlays-Use-preferred-compatible-strings.patch [moved from target/linux/bcm27xx/patches-5.4/950-0412-overlays-Use-preferred-compatible-strings.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0401-tty-amba-pl011-Add-un-throttle-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0413-tty-amba-pl011-Add-un-throttle-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0402-Fix-i2c-pwm-pca9685a-overlay.patch [moved from target/linux/bcm27xx/patches-5.4/950-0414-Fix-i2c-pwm-pca9685a-overlay.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0403-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0415-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0404-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch [moved from target/linux/bcm27xx/patches-5.4/950-0416-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0405-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch [moved from target/linux/bcm27xx/patches-5.4/950-0417-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0406-pisound-Added-reading-Pisound-board-hardware-revisio.patch [moved from target/linux/bcm27xx/patches-5.4/950-0418-pisound-Added-reading-Pisound-board-hardware-revisio.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0407-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch [moved from target/linux/bcm27xx/patches-5.4/950-0419-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0408-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch [moved from target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0409-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch [moved from target/linux/bcm27xx/patches-5.4/950-0422-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch [moved from target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0411-tty-amba-pl011-Avoid-rare-write-when-full-error.patch [moved from target/linux/bcm27xx/patches-5.4/950-0424-tty-amba-pl011-Avoid-rare-write-when-full-error.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0412-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch [moved from target/linux/bcm27xx/patches-5.4/950-0425-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0413-overlays-Correct-the-eth_led-colour-assignments.patch [moved from target/linux/bcm27xx/patches-5.4/950-0426-overlays-Correct-the-eth_led-colour-assignments.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch [moved from target/linux/bcm27xx/patches-5.4/950-0427-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0415-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch [moved from target/linux/bcm27xx/patches-5.4/950-0428-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0416-overlays-dwc2-Increase-RX-FIFO-size.patch [moved from target/linux/bcm27xx/patches-5.4/950-0429-overlays-dwc2-Increase-RX-FIFO-size.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0417-overlays-Fix-mcp23017-s-addr-parameter.patch [moved from target/linux/bcm27xx/patches-5.4/950-0430-overlays-Fix-mcp23017-s-addr-parameter.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0418-SQUASH-Fix-spi-driver-compiler-warnings.patch [moved from target/linux/bcm27xx/patches-5.4/950-0431-SQUASH-Fix-spi-driver-compiler-warnings.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0419-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch [moved from target/linux/bcm27xx/patches-5.4/950-0432-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch [moved from target/linux/bcm27xx/patches-5.4/950-0433-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch [moved from target/linux/bcm27xx/patches-5.4/950-0434-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0421-pcie-brcmstb-Bounce-buffer-support-is-for-BCM2711B0.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch [moved from target/linux/bcm27xx/patches-5.4/950-0436-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch [moved from target/linux/bcm27xx/patches-5.4/950-0437-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch [moved from target/linux/bcm27xx/patches-5.4/950-0438-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Rebuild-downstream-DTS-files.patch [moved from target/linux/bcm27xx/patches-5.4/950-0439-ARM-dts-Rebuild-downstream-DTS-files.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch [moved from target/linux/bcm27xx/patches-5.4/950-0440-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0428-thermal-brcmstb_thermal-Correct-SoC-name.patch [moved from target/linux/bcm27xx/patches-5.4/950-0442-thermal-brcmstb_thermal-Correct-SoC-name.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0429-hwrng-iproc-rng200-Correct-SoC-name.patch [moved from target/linux/bcm27xx/patches-5.4/950-0443-hwrng-iproc-rng200-Correct-SoC-name.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-Correct-SoC-name.patch [moved from target/linux/bcm27xx/patches-5.4/950-0445-ARM-dts-Correct-SoC-name.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0431-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch [moved from target/linux/bcm27xx/patches-5.4/950-0446-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0432-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch [moved from target/linux/bcm27xx/patches-5.4/950-0447-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0433-staging-vchiq_arm-Add-a-matching-unregister-call.patch [moved from target/linux/bcm27xx/patches-5.4/950-0448-staging-vchiq_arm-Add-a-matching-unregister-call.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0434-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch [moved from target/linux/bcm27xx/patches-5.4/950-0449-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0435-ASoC-pcm512x-Fix-unbalanced-regulator-enable-call-in.patch [moved from target/linux/bcm27xx/patches-5.4/950-0450-ASoC-pcm512x-Fix-unbalanced-regulator-enable-call-in.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0436-ARM-dts-overlays-Create-custom-clocks-in.patch [moved from target/linux/bcm27xx/patches-5.4/950-0451-ARM-dts-overlays-Create-custom-clocks-in.patch with 100% similarity]
target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0441-bcm2835-dma-Correct-SoC-name.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0444-pcie-brcmstb-Correct-SoC-name.patch [deleted file]
target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0464-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch [moved from target/linux/bcm27xx/patches-5.4/950-0312-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch with 64% similarity]
target/linux/bcm27xx/patches-5.4/950-0465-overlays-imx219-Correct-link-frequency-to-match-the-.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0466-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0468-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0469-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0470-media-ov5647-Add-extra-10-bit-sensor-modes.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0471-media-ov5647-change-defaults-to-better-match-raw-cam.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0472-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0473-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch [new file with mode: 0644]
target/linux/bcm27xx/patches-5.4/950-0474-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch [new file with mode: 0644]

index 57c176d1681b60d04e7184f3e1cc04fc29e977db..ca86cb39f66ff3c524c6db5954d4eb344bf454a5 100644 (file)
@@ -184,7 +184,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_FREEZER=y
-# CONFIG_FSL_QDMA is not set
 CONFIG_FS_IOMAP=y
 CONFIG_FS_MBCACHE=y
 CONFIG_FS_POSIX_ACL=y
@@ -286,10 +285,7 @@ CONFIG_MAX_RAW_DEVS=256
 CONFIG_MEMFD_CREATE=y
 CONFIG_MEMORY_ISOLATION=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
 # CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGHT_HAVE_CACHE_L2X0=y
 CONFIG_MIGRATION=y
index 6713aef789b3ea151e48fe92a9fe2eff02d07910..53734900b676c0797c690870735219c04e2b5398 100644 (file)
@@ -30,14 +30,12 @@ CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 CONFIG_ARCH_KEEP_MEMBLOCK=y
 CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
-# CONFIG_ARCH_MILBEAUT is not set
 CONFIG_ARCH_MULTIPLATFORM=y
 CONFIG_ARCH_MULTI_V6_V7=y
 CONFIG_ARCH_MULTI_V7=y
 CONFIG_ARCH_NR_GPIO=0
 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
 CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
-# CONFIG_ARCH_RDA is not set
 CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
 CONFIG_ARCH_SUPPORTS_UPROBES=y
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -52,9 +50,6 @@ CONFIG_ARM_ARCH_TIMER=y
 CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
 # CONFIG_ARM_BCM2835_CPUFREQ is not set
 CONFIG_ARM_CPU_SUSPEND=y
-# CONFIG_ARM_ERRATA_814220 is not set
-# CONFIG_ARM_ERRATA_857271 is not set
-# CONFIG_ARM_ERRATA_857272 is not set
 CONFIG_ARM_GIC=y
 CONFIG_ARM_HAS_SG_CHAIN=y
 CONFIG_ARM_L1_CACHE_SHIFT=6
@@ -212,7 +207,6 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_EDAC_ATOMIC_SCRUB=y
 CONFIG_EDAC_SUPPORT=y
 CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -242,7 +236,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_FREEZER=y
-# CONFIG_FSL_QDMA is not set
 CONFIG_FS_ENCRYPTION=y
 CONFIG_FS_IOMAP=y
 CONFIG_FS_MBCACHE=y
@@ -277,7 +270,6 @@ CONFIG_GPIOLIB_IRQCHIP=y
 CONFIG_GPIO_BCM_VIRT=y
 CONFIG_GPIO_RASPBERRYPI_EXP=y
 CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
 CONFIG_HANDLE_DOMAIN_IRQ=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_HARDIRQS_SW_RESEND=y
@@ -370,10 +362,7 @@ CONFIG_MDIO_DEVICE=y
 CONFIG_MEMFD_CREATE=y
 CONFIG_MEMORY_ISOLATION=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
 # CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MICROCHIP_PHY=y
 CONFIG_MIGHT_HAVE_CACHE_L2X0=y
@@ -427,11 +416,9 @@ CONFIG_PCI=y
 CONFIG_PCIEAER=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCIE_BRCMSTB=y
-# CONFIG_PCIE_BW is not set
 CONFIG_PCIE_PME=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MSI_IRQ_DOMAIN=y
 CONFIG_PERF_USE_VMALLOC=y
@@ -512,7 +499,6 @@ CONFIG_TIMER_PROBE=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_TREE_RCU=y
 CONFIG_TREE_SRCU=y
-# CONFIG_TRUSTED_FOUNDATIONS is not set
 CONFIG_UEVENT_HELPER_PATH=""
 # CONFIG_UID16 is not set
 CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
index 7527c3fdd96191c84519799a48b9cb6eefd8e027..587c64b75755e89c11f5b2d5ec83e0deef74a8c2 100644 (file)
@@ -157,6 +157,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_MQ_PCI=y
 CONFIG_BLK_PM=y
 CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BOUNCE=y
 CONFIG_BRCMSTB_THERMAL=y
 CONFIG_BRCM_CHAR_DRIVERS=y
 CONFIG_CAVIUM_ERRATUM_22375=y
@@ -253,7 +254,6 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_EDAC_SUPPORT=y
 CONFIG_EFI_EARLYCON=y
 CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -283,7 +283,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_FRAME_POINTER=y
 CONFIG_FREEZER=y
 CONFIG_FSL_ERRATUM_A008585=y
-# CONFIG_FSL_QDMA is not set
 CONFIG_FS_ENCRYPTION=y
 CONFIG_FS_IOMAP=y
 CONFIG_FS_MBCACHE=y
@@ -323,7 +322,6 @@ CONFIG_GPIOLIB_IRQCHIP=y
 CONFIG_GPIO_BCM_VIRT=y
 CONFIG_GPIO_RASPBERRYPI_EXP=y
 CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
 CONFIG_HANDLE_DOMAIN_IRQ=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_HARDIRQS_SW_RESEND=y
@@ -446,10 +444,7 @@ CONFIG_MEMFD_CREATE=y
 # CONFIG_MEMORY_HOTPLUG is not set
 CONFIG_MEMORY_ISOLATION=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
 # CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MICROCHIP_PHY=y
 CONFIG_MIGRATION=y
@@ -481,7 +476,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=4
 # CONFIG_NUMA is not set
 CONFIG_NVMEM=y
-# CONFIG_NVMEM_REBOOT_MODE is not set
 # CONFIG_OCTEONTX2_AF is not set
 CONFIG_OF=y
 CONFIG_OF_ADDRESS=y
@@ -503,7 +497,6 @@ CONFIG_PCI=y
 # CONFIG_PCIE_BRCMSTB is not set
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MSI_IRQ_DOMAIN=y
 CONFIG_PGTABLE_LEVELS=3
index a813eb586cdd71f63a2df42cdbf79a08673b42a1..a4ab0656cb895d3447ea325fa0d7853158eb5a0c 100644 (file)
@@ -160,6 +160,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_MQ_PCI=y
 CONFIG_BLK_PM=y
 CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BOUNCE=y
 CONFIG_BRCMSTB_THERMAL=y
 CONFIG_BRCM_CHAR_DRIVERS=y
 CONFIG_BROADCOM_PHY=y
@@ -258,7 +259,6 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_EDAC_SUPPORT=y
 CONFIG_EFI_EARLYCON=y
 CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -288,7 +288,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_FRAME_POINTER=y
 CONFIG_FREEZER=y
 CONFIG_FSL_ERRATUM_A008585=y
-# CONFIG_FSL_QDMA is not set
 CONFIG_FS_ENCRYPTION=y
 CONFIG_FS_IOMAP=y
 CONFIG_FS_MBCACHE=y
@@ -329,7 +328,6 @@ CONFIG_GPIOLIB_IRQCHIP=y
 CONFIG_GPIO_BCM_VIRT=y
 CONFIG_GPIO_RASPBERRYPI_EXP=y
 CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
 CONFIG_HANDLE_DOMAIN_IRQ=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_HARDIRQS_SW_RESEND=y
@@ -453,10 +451,7 @@ CONFIG_MEMFD_CREATE=y
 # CONFIG_MEMORY_HOTPLUG is not set
 CONFIG_MEMORY_ISOLATION=y
 CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
 # CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
 CONFIG_MMC=y
@@ -487,7 +482,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=4
 # CONFIG_NUMA is not set
 CONFIG_NVMEM=y
-# CONFIG_NVMEM_REBOOT_MODE is not set
 # CONFIG_OCTEONTX2_AF is not set
 CONFIG_OF=y
 CONFIG_OF_ADDRESS=y
@@ -509,11 +503,9 @@ CONFIG_PCIEAER=y
 CONFIG_PCIEPORTBUS=y
 # CONFIG_PCIE_AL is not set
 CONFIG_PCIE_BRCMSTB=y
-# CONFIG_PCIE_BW is not set
 CONFIG_PCIE_PME=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MSI_IRQ_DOMAIN=y
 CONFIG_PGTABLE_LEVELS=3
diff --git a/target/linux/bcm27xx/patches-5.4/950-0205-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0205-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch
deleted file mode 100644 (file)
index 8fd54b1..0000000
+++ /dev/null
@@ -1,1187 +0,0 @@
-From 79624ca23c53064fefee774a89952a587b72cc01 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
- driver
-
-This commit adds the basic Broadcom STB PCIe controller.  Missing is
-the ability to process MSI and also handle dma-ranges for inbound
-memory accesses.  These two functionalities are added in subsequent
-commits.
-
-The PCIe block contains an MDIO interface.  This is a local interface
-only accessible by the PCIe controller.  It cannot be used or shared
-by any other HW.  As such, the small amount of code for this
-controller is included in this driver as there is little upside to put
-it elsewhere.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/Kconfig        |    9 +
- drivers/pci/controller/Makefile       |    2 +-
- drivers/pci/controller/pcie-brcmstb.c | 1097 +++++++++++++++++++++++++
- include/soc/brcmstb/memory_api.h      |   25 +
- 4 files changed, 1132 insertions(+), 1 deletion(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb.c
- create mode 100644 include/soc/brcmstb/memory_api.h
-
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -288,5 +288,14 @@ config PCI_HYPERV_INTERFACE
-         The Hyper-V PCI Interface is a helper driver allows other drivers to
-         have a common interface with the Hyper-V PCI frontend driver.
-+config PCIE_BRCMSTB
-+      tristate "Broadcom Brcmstb PCIe platform host driver"
-+      depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+      depends on OF
-+      depends on SOC_BRCMSTB
-+      default ARCH_BRCMSTB || BMIPS_GENERIC
-+      help
-+        Adds support for Broadcom Settop Box PCIe host controller.
-+
- source "drivers/pci/controller/dwc/Kconfig"
- endmenu
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -29,11 +29,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie
- obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y                         += dwc/
--
- # The following drivers are for devices that use the generic ACPI
- # pci_root.c driver but don't support standard ECAM config access.
- # They contain MCFG quirks to replace the generic ECAM accessors with
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -0,0 +1,1097 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright (C) 2009 - 2017 Broadcom */
-+
-+#include <linux/clk.h>
-+#include <linux/compiler.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/irqdomain.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/log2.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
-+#include <linux/pci.h>
-+#include <linux/printk.h>
-+#include <linux/sizes.h>
-+#include <linux/slab.h>
-+#include <soc/brcmstb/memory_api.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include "../pci.h"
-+
-+/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
-+#define BRCM_PCIE_CAP_REGS                            0x00ac
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Offsets. The names are from
-+ * the chip's RDB and we use them here so that a script can correlate
-+ * this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1               0x0188
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3                     0x043c
-+#define PCIE_RC_DL_MDIO_ADDR                          0x1100
-+#define PCIE_RC_DL_MDIO_WR_DATA                               0x1104
-+#define PCIE_RC_DL_MDIO_RD_DATA                               0x1108
-+#define PCIE_MISC_MISC_CTRL                           0x4008
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO              0x400c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI              0x4010
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO                   0x402c
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO                   0x4034
-+#define PCIE_MISC_RC_BAR2_CONFIG_HI                   0x4038
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO                   0x403c
-+#define PCIE_MISC_PCIE_CTRL                           0x4064
-+#define PCIE_MISC_PCIE_STATUS                         0x4068
-+#define PCIE_MISC_REVISION                            0x406c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT      0x4070
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI         0x4080
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI                0x4084
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG                        0x4204
-+#define PCIE_INTR2_CPU_BASE                           0x4300
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Field shift and mask info. The
-+ * names are from the chip's RDB and we use them here so that a script
-+ * can correlate this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT        0x2
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK             0xffffff
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_SHIFT            0x0
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK                        0x1000
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_SHIFT                       0xc
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK             0x2000
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_SHIFT            0xd
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK                       0x300000
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT              0x14
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK                    0xf8000000
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT                   0x1b
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK                    0x7c00000
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_SHIFT                   0x16
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK                    0x1f
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_SHIFT                   0x0
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK                 0x1f
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_SHIFT                        0x0
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK                 0x1f
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_SHIFT                        0x0
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK                 0x1f
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_SHIFT                        0x0
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK                  0x4
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_SHIFT                 0x2
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK             0x1
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_SHIFT            0x0
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK                  0x80
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_SHIFT                 0x7
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK             0x20
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_SHIFT            0x5
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK             0x10
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_SHIFT            0x4
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK           0x40
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_SHIFT          0x6
-+#define PCIE_MISC_REVISION_MAJMIN_MASK                                0xffff
-+#define PCIE_MISC_REVISION_MAJMIN_SHIFT                               0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK   0xfff00000
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_SHIFT  0x14
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK    0xfff0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_SHIFT   0x4
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS        0xc
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK               0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_SHIFT      0x0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK     0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_SHIFT    0x0
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK       0x2
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_SHIFT 0x1
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK               0x08000000
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_SHIFT      0x1b
-+#define PCIE_RGR1_SW_INIT_1_PERST_MASK                                0x1
-+#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT                               0x0
-+
-+#define BRCM_NUM_PCIE_OUT_WINS                0x4
-+#define BRCM_MAX_SCB                  0x4
-+
-+#define BRCM_MSI_TARGET_ADDR_LT_4GB   0x0fffffffcULL
-+#define BRCM_MSI_TARGET_ADDR_GT_4GB   0xffffffffcULL
-+
-+#define BURST_SIZE_128                        0
-+#define BURST_SIZE_256                        1
-+#define BURST_SIZE_512                        2
-+
-+/* Offsets from PCIE_INTR2_CPU_BASE */
-+#define STATUS                                0x0
-+#define SET                           0x4
-+#define CLR                           0x8
-+#define MASK_STATUS                   0xc
-+#define MASK_SET                      0x10
-+#define MASK_CLR                      0x14
-+
-+#define PCIE_BUSNUM_SHIFT             20
-+#define PCIE_SLOT_SHIFT                       15
-+#define PCIE_FUNC_SHIFT                       12
-+
-+#if defined(__BIG_ENDIAN)
-+#define       DATA_ENDIAN                     2       /* PCIe->DDR inbound traffic */
-+#define MMIO_ENDIAN                   2       /* CPU->PCIe outbound traffic */
-+#else
-+#define       DATA_ENDIAN                     0
-+#define MMIO_ENDIAN                   0
-+#endif
-+
-+#define MDIO_PORT0                    0x0
-+#define MDIO_DATA_MASK                        0x7fffffff
-+#define MDIO_DATA_SHIFT                       0x0
-+#define MDIO_PORT_MASK                        0xf0000
-+#define MDIO_PORT_SHIFT                       0x16
-+#define MDIO_REGAD_MASK                       0xffff
-+#define MDIO_REGAD_SHIFT              0x0
-+#define MDIO_CMD_MASK                 0xfff00000
-+#define MDIO_CMD_SHIFT                        0x14
-+#define MDIO_CMD_READ                 0x1
-+#define MDIO_CMD_WRITE                        0x0
-+#define MDIO_DATA_DONE_MASK           0x80000000
-+#define MDIO_RD_DONE(x)                       (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
-+#define MDIO_WT_DONE(x)                       (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
-+#define SSC_REGS_ADDR                 0x1100
-+#define SET_ADDR_OFFSET                       0x1f
-+#define SSC_CNTL_OFFSET                       0x2
-+#define SSC_CNTL_OVRD_EN_MASK         0x8000
-+#define SSC_CNTL_OVRD_EN_SHIFT                0xf
-+#define SSC_CNTL_OVRD_VAL_MASK                0x4000
-+#define SSC_CNTL_OVRD_VAL_SHIFT               0xe
-+#define SSC_STATUS_OFFSET             0x1
-+#define SSC_STATUS_SSC_MASK           0x400
-+#define SSC_STATUS_SSC_SHIFT          0xa
-+#define SSC_STATUS_PLL_LOCK_MASK      0x800
-+#define SSC_STATUS_PLL_LOCK_SHIFT     0xb
-+
-+#define IDX_ADDR(pcie)        \
-+      ((pcie)->reg_offsets[EXT_CFG_INDEX])
-+#define DATA_ADDR(pcie)       \
-+      ((pcie)->reg_offsets[EXT_CFG_DATA])
-+#define PCIE_RGR1_SW_INIT_1(pcie) \
-+      ((pcie)->reg_offsets[RGR1_SW_INIT_1])
-+
-+enum {
-+      RGR1_SW_INIT_1,
-+      EXT_CFG_INDEX,
-+      EXT_CFG_DATA,
-+};
-+
-+enum {
-+      RGR1_SW_INIT_1_INIT_MASK,
-+      RGR1_SW_INIT_1_INIT_SHIFT,
-+      RGR1_SW_INIT_1_PERST_MASK,
-+      RGR1_SW_INIT_1_PERST_SHIFT,
-+};
-+
-+enum pcie_type {
-+      BCM7425,
-+      BCM7435,
-+      GENERIC,
-+      BCM7278,
-+};
-+
-+struct brcm_window {
-+      dma_addr_t pcie_addr;
-+      phys_addr_t cpu_addr;
-+      dma_addr_t size;
-+};
-+
-+/* Internal PCIe Host Controller Information.*/
-+struct brcm_pcie {
-+      struct device           *dev;
-+      void __iomem            *base;
-+      struct list_head        resources;
-+      int                     irq;
-+      struct clk              *clk;
-+      struct pci_bus          *root_bus;
-+      struct device_node      *dn;
-+      int                     id;
-+      bool                    suspended;
-+      int                     num_out_wins;
-+      bool                    ssc;
-+      int                     gen;
-+      struct brcm_window      out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+      unsigned int            rev;
-+      const int               *reg_offsets;
-+      const int               *reg_field_info;
-+      enum pcie_type          type;
-+};
-+
-+struct pcie_cfg_data {
-+      const int *reg_field_info;
-+      const int *offsets;
-+      const enum pcie_type type;
-+};
-+
-+static const int pcie_reg_field_info[] = {
-+      [RGR1_SW_INIT_1_INIT_MASK] = 0x2,
-+      [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1,
-+};
-+
-+static const int pcie_reg_field_info_bcm7278[] = {
-+      [RGR1_SW_INIT_1_INIT_MASK] = 0x1,
-+      [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0,
-+};
-+
-+static const int pcie_offset_bcm7425[] = {
-+      [RGR1_SW_INIT_1] = 0x8010,
-+      [EXT_CFG_INDEX]  = 0x8300,
-+      [EXT_CFG_DATA]   = 0x8304,
-+};
-+
-+static const struct pcie_cfg_data bcm7425_cfg = {
-+      .reg_field_info = pcie_reg_field_info,
-+      .offsets        = pcie_offset_bcm7425,
-+      .type           = BCM7425,
-+};
-+
-+static const int pcie_offsets[] = {
-+      [RGR1_SW_INIT_1] = 0x9210,
-+      [EXT_CFG_INDEX]  = 0x9000,
-+      [EXT_CFG_DATA]   = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7435_cfg = {
-+      .reg_field_info = pcie_reg_field_info,
-+      .offsets        = pcie_offsets,
-+      .type           = BCM7435,
-+};
-+
-+static const struct pcie_cfg_data generic_cfg = {
-+      .reg_field_info = pcie_reg_field_info,
-+      .offsets        = pcie_offsets,
-+      .type           = GENERIC,
-+};
-+
-+static const int pcie_offset_bcm7278[] = {
-+      [RGR1_SW_INIT_1] = 0xc010,
-+      [EXT_CFG_INDEX] = 0x9000,
-+      [EXT_CFG_DATA] = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7278_cfg = {
-+      .reg_field_info = pcie_reg_field_info_bcm7278,
-+      .offsets        = pcie_offset_bcm7278,
-+      .type           = BCM7278,
-+};
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+                                      int where);
-+
-+static struct pci_ops brcm_pcie_ops = {
-+      .map_bus = brcm_pcie_map_conf,
-+      .read = pci_generic_config_read,
-+      .write = pci_generic_config_write,
-+};
-+
-+#if defined(CONFIG_MIPS)
-+/* Broadcom MIPs HW implicitly does the swapping if necessary */
-+#define bcm_readl(a)          __raw_readl(a)
-+#define bcm_writel(d, a)      __raw_writel(d, a)
-+#define bcm_readw(a)          __raw_readw(a)
-+#define bcm_writew(d, a)      __raw_writew(d, a)
-+#else
-+#define bcm_readl(a)          readl(a)
-+#define bcm_writel(d, a)      writel(d, a)
-+#define bcm_readw(a)          readw(a)
-+#define bcm_writew(d, a)      writew(d, a)
-+#endif
-+
-+/* These macros extract/insert fields to host controller's register set. */
-+#define RD_FLD(base, reg, field) \
-+      rd_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT)
-+#define WR_FLD(base, reg, field, val) \
-+      wr_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_RB(base, reg, field, val) \
-+      wr_fld_rb(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_WITH_OFFSET(base, off, reg, field, val) \
-+      wr_fld(base + reg + off, reg##_##field##_MASK, \
-+             reg##_##field##_SHIFT, val)
-+#define EXTRACT_FIELD(val, reg, field) \
-+      ((val & reg##_##field##_MASK) >> reg##_##field##_SHIFT)
-+#define INSERT_FIELD(val, reg, field, field_val) \
-+      ((val & ~reg##_##field##_MASK) | \
-+       (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-+
-+static phys_addr_t scb_size[BRCM_MAX_SCB];
-+static int num_memc;
-+static int num_pcie;
-+static DEFINE_MUTEX(brcm_pcie_lock);
-+
-+static u32 rd_fld(void __iomem *p, u32 mask, int shift)
-+{
-+      return (bcm_readl(p) & mask) >> shift;
-+}
-+
-+static void wr_fld(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+      u32 reg = bcm_readl(p);
-+
-+      reg = (reg & ~mask) | ((val << shift) & mask);
-+      bcm_writel(reg, p);
-+}
-+
-+static void wr_fld_rb(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+      wr_fld(p, mask, shift, val);
-+      (void)bcm_readl(p);
-+}
-+
-+static const char *link_speed_to_str(int s)
-+{
-+      switch (s) {
-+      case 1:
-+              return "2.5";
-+      case 2:
-+              return "5.0";
-+      case 3:
-+              return "8.0";
-+      default:
-+              break;
-+      }
-+      return "???";
-+}
-+
-+/*
-+ * The roundup_pow_of_two() from log2.h invokes
-+ * __roundup_pow_of_two(unsigned long), but we really need a
-+ * such a function to take a native u64 since unsigned long
-+ * is 32 bits on some configurations.  So we provide this helper
-+ * function below.
-+ */
-+static u64 roundup_pow_of_two_64(u64 n)
-+{
-+      return 1ULL << fls64(n - 1);
-+}
-+
-+/*
-+ * This is to convert the size of the inbound "BAR" region to the
-+ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
-+ */
-+int encode_ibar_size(u64 size)
-+{
-+      int log2_in = ilog2(size);
-+
-+      if (log2_in >= 12 && log2_in <= 15)
-+              /* Covers 4KB to 32KB (inclusive) */
-+              return (log2_in - 12) + 0x1c;
-+      else if (log2_in >= 16 && log2_in <= 37)
-+              /* Covers 64KB to 32GB, (inclusive) */
-+              return log2_in - 15;
-+      /* Something is awry so disable */
-+      return 0;
-+}
-+
-+static u32 mdio_form_pkt(int port, int regad, int cmd)
-+{
-+      u32 pkt = 0;
-+
-+      pkt |= (port << MDIO_PORT_SHIFT) & MDIO_PORT_MASK;
-+      pkt |= (regad << MDIO_REGAD_SHIFT) & MDIO_REGAD_MASK;
-+      pkt |= (cmd << MDIO_CMD_SHIFT) & MDIO_CMD_MASK;
-+
-+      return pkt;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_read(void __iomem *base, u8 port, u8 regad)
-+{
-+      int tries;
-+      u32 data;
-+
-+      bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_READ),
-+                 base + PCIE_RC_DL_MDIO_ADDR);
-+      bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+
-+      data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+      for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
-+              udelay(10);
-+              data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+      }
-+
-+      return MDIO_RD_DONE(data)
-+              ? (data & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT
-+              : -EIO;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_write(void __iomem *base, u8 port, u8 regad, u16 wrdata)
-+{
-+      int tries;
-+      u32 data;
-+
-+      bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
-+                 base + PCIE_RC_DL_MDIO_ADDR);
-+      bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+      bcm_writel(MDIO_DATA_DONE_MASK | wrdata,
-+                 base + PCIE_RC_DL_MDIO_WR_DATA);
-+
-+      data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+      for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
-+              udelay(10);
-+              data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+      }
-+
-+      return MDIO_WT_DONE(data) ? 0 : -EIO;
-+}
-+
-+/*
-+ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
-+ * return value indicates error.
-+ */
-+static int set_ssc(void __iomem *base)
-+{
-+      int tmp;
-+      u16 wrdata;
-+      int pll, ssc;
-+
-+      tmp = mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET, SSC_REGS_ADDR);
-+      if (tmp < 0)
-+              return tmp;
-+
-+      tmp = mdio_read(base, MDIO_PORT0, SSC_CNTL_OFFSET);
-+      if (tmp < 0)
-+              return tmp;
-+
-+      wrdata = INSERT_FIELD(tmp, SSC_CNTL_OVRD, EN, 1);
-+      wrdata = INSERT_FIELD(wrdata, SSC_CNTL_OVRD, VAL, 1);
-+      tmp = mdio_write(base, MDIO_PORT0, SSC_CNTL_OFFSET, wrdata);
-+      if (tmp < 0)
-+              return tmp;
-+
-+      usleep_range(1000, 2000);
-+      tmp = mdio_read(base, MDIO_PORT0, SSC_STATUS_OFFSET);
-+      if (tmp < 0)
-+              return tmp;
-+
-+      ssc = EXTRACT_FIELD(tmp, SSC_STATUS, SSC);
-+      pll = EXTRACT_FIELD(tmp, SSC_STATUS, PLL_LOCK);
-+
-+      return (ssc && pll) ? 0 : -EIO;
-+}
-+
-+/* Limits operation to a specific generation (1, 2, or 3) */
-+static void set_gen(void __iomem *base, int gen)
-+{
-+      u32 lnkcap = bcm_readl(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+      u16 lnkctl2 = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+
-+      lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
-+      bcm_writel(lnkcap, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+
-+      lnkctl2 = (lnkctl2 & ~0xf) | gen;
-+      bcm_writew(lnkctl2, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+}
-+
-+static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
-+                                     unsigned int win, phys_addr_t cpu_addr,
-+                                     dma_addr_t  pcie_addr, dma_addr_t size)
-+{
-+      void __iomem *base = pcie->base;
-+      phys_addr_t cpu_addr_mb, limit_addr_mb;
-+      u32 tmp;
-+
-+      /* Set the base of the pcie_addr window */
-+      bcm_writel(lower_32_bits(pcie_addr) + MMIO_ENDIAN,
-+                 base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + (win * 8));
-+      bcm_writel(upper_32_bits(pcie_addr),
-+                 base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + (win * 8));
-+
-+      cpu_addr_mb = cpu_addr >> 20;
-+      limit_addr_mb = (cpu_addr + size - 1) >> 20;
-+
-+      /* Write the addr base low register */
-+      WR_FLD_WITH_OFFSET(base, (win * 4),
-+                         PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+                         BASE, cpu_addr_mb);
-+      /* Write the addr limit low register */
-+      WR_FLD_WITH_OFFSET(base, (win * 4),
-+                         PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+                         LIMIT, limit_addr_mb);
-+
-+      if (pcie->type != BCM7435 && pcie->type != BCM7425) {
-+              /* Write the cpu addr high register */
-+              tmp = (u32)(cpu_addr_mb >>
-+                      PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+              WR_FLD_WITH_OFFSET(base, (win * 8),
-+                                 PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
-+                                 BASE, tmp);
-+              /* Write the cpu limit high register */
-+              tmp = (u32)(limit_addr_mb >>
-+                      PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+              WR_FLD_WITH_OFFSET(base, (win * 8),
-+                                 PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
-+                                 LIMIT, tmp);
-+      }
-+}
-+
-+/* Configuration space read/write support */
-+static int cfg_index(int busnr, int devfn, int reg)
-+{
-+      return ((PCI_SLOT(devfn) & 0x1f) << PCIE_SLOT_SHIFT)
-+              | ((PCI_FUNC(devfn) & 0x07) << PCIE_FUNC_SHIFT)
-+              | (busnr << PCIE_BUSNUM_SHIFT)
-+              | (reg & ~3);
-+}
-+
-+/* The controller is capable of serving in both RC and EP roles */
-+static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
-+{
-+      void __iomem *base = pcie->base;
-+      u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+
-+      return !!EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PORT);
-+}
-+
-+static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
-+{
-+      void __iomem *base = pcie->base;
-+      u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+      u32 dla = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_DL_ACTIVE);
-+      u32 plu = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PHYLINKUP);
-+
-+      return  (dla && plu) ? true : false;
-+}
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+                                      int where)
-+{
-+      struct brcm_pcie *pcie = bus->sysdata;
-+      void __iomem *base = pcie->base;
-+      int idx;
-+
-+      /* Accesses to the RC go right to the RC registers if slot==0 */
-+      if (pci_is_root_bus(bus))
-+              return PCI_SLOT(devfn) ? NULL : base + where;
-+
-+      /* For devices, write to the config space index register */
-+      idx = cfg_index(bus->number, devfn, where);
-+      bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
-+      return base + DATA_ADDR(pcie) + (where & 0x3);
-+}
-+
-+static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-+                                              unsigned int val)
-+{
-+      unsigned int shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT];
-+      u32 mask =  pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK];
-+
-+      wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie), mask, shift, val);
-+}
-+
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+                                     unsigned int val)
-+{
-+      if (pcie->type != BCM7278)
-+              wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie),
-+                        PCIE_RGR1_SW_INIT_1_PERST_MASK,
-+                        PCIE_RGR1_SW_INIT_1_PERST_SHIFT, val);
-+      else
-+              /* Assert = 0, de-assert = 1 on 7278 */
-+              WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
-+}
-+
-+static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
-+{
-+      int i, ret = 0;
-+
-+      mutex_lock(&brcm_pcie_lock);
-+      if (num_pcie > 0) {
-+              num_pcie++;
-+              goto done;
-+      }
-+
-+      /* Determine num_memc and their sizes */
-+      for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+              u64 size = brcmstb_memory_memc_size(i);
-+
-+              if (size == (u64)-1) {
-+                      dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+                      ret = -EINVAL;
-+                      goto done;
-+              } else if (size) {
-+                      scb_size[i] = roundup_pow_of_two_64(size);
-+                      num_memc++;
-+              } else {
-+                      break;
-+              }
-+      }
-+      if (!ret && num_memc == 0) {
-+              ret = -EINVAL;
-+              goto done;
-+      }
-+
-+      num_pcie++;
-+done:
-+      mutex_unlock(&brcm_pcie_lock);
-+      return ret;
-+}
-+
-+static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
-+{
-+      mutex_lock(&brcm_pcie_lock);
-+      if (--num_pcie == 0)
-+              num_memc = 0;
-+      mutex_unlock(&brcm_pcie_lock);
-+}
-+
-+static int brcm_pcie_parse_request_of_pci_ranges(struct brcm_pcie *pcie)
-+{
-+      struct resource_entry *win;
-+      int ret;
-+
-+      ret = devm_of_pci_get_host_bridge_resources(pcie->dev, 0, 0xff,
-+                                                  &pcie->resources, NULL);
-+      if (ret) {
-+              dev_err(pcie->dev, "failed to get host resources\n");
-+              return ret;
-+      }
-+
-+      resource_list_for_each_entry(win, &pcie->resources) {
-+              struct resource *parent, *res = win->res;
-+              dma_addr_t offset = (dma_addr_t)win->offset;
-+
-+              if (resource_type(res) == IORESOURCE_IO) {
-+                      parent = &ioport_resource;
-+              } else if (resource_type(res) == IORESOURCE_MEM) {
-+                      if (pcie->num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
-+                              dev_err(pcie->dev, "too many outbound wins\n");
-+                              return -EINVAL;
-+                      }
-+                      pcie->out_wins[pcie->num_out_wins].cpu_addr
-+                              = (phys_addr_t)res->start;
-+                      pcie->out_wins[pcie->num_out_wins].pcie_addr
-+                              = (dma_addr_t)(res->start
-+                                             - (phys_addr_t)offset);
-+                      pcie->out_wins[pcie->num_out_wins].size
-+                              = (dma_addr_t)(res->end - res->start + 1);
-+                      pcie->num_out_wins++;
-+                      parent = &iomem_resource;
-+              } else {
-+                      continue;
-+              }
-+
-+              ret = devm_request_resource(pcie->dev, parent, res);
-+              if (ret) {
-+                      dev_err(pcie->dev, "failed to get res %pR\n", res);
-+                      return ret;
-+              }
-+      }
-+      return 0;
-+}
-+
-+static int brcm_pcie_setup(struct brcm_pcie *pcie)
-+{
-+      void __iomem *base = pcie->base;
-+      unsigned int scb_size_val;
-+      u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
-+      u32 tmp, burst;
-+      int i, j, ret, limit;
-+      u16 nlw, cls, lnksta;
-+      bool ssc_good = false;
-+      struct device *dev = pcie->dev;
-+
-+      /* Reset the bridge */
-+      brcm_pcie_bridge_sw_init_set(pcie, 1);
-+
-+      /*
-+       * Ensure that the fundamental reset is asserted, except for 7278,
-+       * which fails if we do this.
-+       */
-+      if (pcie->type != BCM7278)
-+              brcm_pcie_perst_set(pcie, 1);
-+
-+      usleep_range(100, 200);
-+
-+      /* Take the bridge out of reset */
-+      brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+      WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+      /* Wait for SerDes to be stable */
-+      usleep_range(100, 200);
-+
-+      /* Grab the PCIe hw revision number */
-+      tmp = bcm_readl(base + PCIE_MISC_REVISION);
-+      pcie->rev = EXTRACT_FIELD(tmp, PCIE_MISC_REVISION, MAJMIN);
-+
-+      /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
-+      tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
-+      tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
-+      burst = (pcie->type == GENERIC || pcie->type == BCM7278)
-+              ? BURST_SIZE_512 : BURST_SIZE_256;
-+      tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+      bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-+
-+      /*
-+       * Set up inbound memory view for the EP (called RC_BAR2,
-+       * not to be confused with the BARs that are advertised by
-+       * the EP).
-+       */
-+      for (i = 0; i < num_memc; i++)
-+              total_mem_size += scb_size[i];
-+
-+      /*
-+       * The PCIe host controller by design must set the inbound
-+       * viewport to be a contiguous arrangement of all of the
-+       * system's memory.  In addition, its size mut be a power of
-+       * two.  To further complicate matters, the viewport must
-+       * start on a pcie-address that is aligned on a multiple of its
-+       * size.  If a portion of the viewport does not represent
-+       * system memory -- e.g. 3GB of memory requires a 4GB viewport
-+       * -- we can map the outbound memory in or after 3GB and even
-+       * though the viewport will overlap the outbound memory the
-+       * controller will know to send outbound memory downstream and
-+       * everything else upstream.
-+       */
-+      rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-+
-+      /*
-+       * Set simple configuration based on memory sizes
-+       * only.  We always start the viewport at address 0.
-+       */
-+      rc_bar2_offset = 0;
-+
-+      tmp = lower_32_bits(rc_bar2_offset);
-+      tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-+                         encode_ibar_size(rc_bar2_size));
-+      bcm_writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
-+      bcm_writel(upper_32_bits(rc_bar2_offset),
-+                 base + PCIE_MISC_RC_BAR2_CONFIG_HI);
-+
-+      scb_size_val = scb_size[0]
-+              ? ilog2(scb_size[0]) - 15 : 0xf; /* 0xf is 1GB */
-+      WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB0_SIZE, scb_size_val);
-+
-+      if (num_memc > 1) {
-+              scb_size_val = scb_size[1]
-+                      ? ilog2(scb_size[1]) - 15 : 0xf; /* 0xf is 1GB */
-+              WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB1_SIZE, scb_size_val);
-+      }
-+
-+      if (num_memc > 2) {
-+              scb_size_val = scb_size[2]
-+                      ? ilog2(scb_size[2]) - 15 : 0xf; /* 0xf is 1GB */
-+              WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB2_SIZE, scb_size_val);
-+      }
-+
-+      /* disable the PCIe->GISB memory window (RC_BAR1) */
-+      WR_FLD(base, PCIE_MISC_RC_BAR1_CONFIG_LO, SIZE, 0);
-+
-+      /* disable the PCIe->SCB memory window (RC_BAR3) */
-+      WR_FLD(base, PCIE_MISC_RC_BAR3_CONFIG_LO, SIZE, 0);
-+
-+      if (!pcie->suspended) {
-+              /* clear any interrupts we find on boot */
-+              bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + CLR);
-+              (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + CLR);
-+      }
-+
-+      /* Mask all interrupts since we are not handling any yet */
-+      bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+      (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+
-+      if (pcie->gen)
-+              set_gen(base, pcie->gen);
-+
-+      /* Unassert the fundamental reset */
-+      brcm_pcie_perst_set(pcie, 0);
-+
-+      /*
-+       * Give the RC/EP time to wake up, before trying to configure RC.
-+       * Intermittently check status for link-up, up to a total of 100ms
-+       * when we don't know if the device is there, and up to 1000ms if
-+       * we do know the device is there.
-+       */
-+      limit = pcie->suspended ? 1000 : 100;
-+      for (i = 1, j = 0; j < limit && !brcm_pcie_link_up(pcie);
-+           j += i, i = i * 2)
-+              msleep(i + j > limit ? limit - j : i);
-+
-+      if (!brcm_pcie_link_up(pcie)) {
-+              dev_info(dev, "link down\n");
-+              return -ENODEV;
-+      }
-+
-+      if (!brcm_pcie_rc_mode(pcie)) {
-+              dev_err(dev, "PCIe misconfigured; is in EP mode\n");
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < pcie->num_out_wins; i++)
-+              brcm_pcie_set_outbound_win(pcie, i, pcie->out_wins[i].cpu_addr,
-+                                         pcie->out_wins[i].pcie_addr,
-+                                         pcie->out_wins[i].size);
-+
-+      /*
-+       * For config space accesses on the RC, show the right class for
-+       * a PCIe-PCIe bridge (the default setting is to be EP mode).
-+       */
-+      WR_FLD_RB(base, PCIE_RC_CFG_PRIV1_ID_VAL3, CLASS_CODE, 0x060400);
-+
-+      if (pcie->ssc) {
-+              ret = set_ssc(base);
-+              if (ret == 0)
-+                      ssc_good = true;
-+              else
-+                      dev_err(dev, "failed attempt to enter ssc mode\n");
-+      }
-+
-+      lnksta = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
-+      cls = lnksta & PCI_EXP_LNKSTA_CLS;
-+      nlw = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-+      dev_info(dev, "link up, %s Gbps x%u %s\n", link_speed_to_str(cls),
-+               nlw, ssc_good ? "(SSC)" : "(!SSC)");
-+
-+      /* PCIe->SCB endian mode for BAR */
-+      /* field ENDIAN_MODE_BAR2 = DATA_ENDIAN */
-+      WR_FLD_RB(base, PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
-+                ENDIAN_MODE_BAR2, DATA_ENDIAN);
-+
-+      /*
-+       * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
-+       * is enabled =>  setting the CLKREQ_DEBUG_ENABLE field to 1.
-+       */
-+      WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, CLKREQ_DEBUG_ENABLE, 1);
-+
-+      return 0;
-+}
-+
-+/* L23 is a low-power PCIe link state */
-+static void enter_l23(struct brcm_pcie *pcie)
-+{
-+      void __iomem *base = pcie->base;
-+      int tries, l23;
-+
-+      /* assert request for L23 */
-+      WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 1);
-+      /* poll L23 status */
-+      for (tries = 0, l23 = 0; tries < 1000 && !l23; tries++)
-+              l23 = RD_FLD(base, PCIE_MISC_PCIE_STATUS, PCIE_LINK_IN_L23);
-+      if (!l23)
-+              dev_err(pcie->dev, "failed to enter L23\n");
-+}
-+
-+static void turn_off(struct brcm_pcie *pcie)
-+{
-+      void __iomem *base = pcie->base;
-+
-+      if (brcm_pcie_link_up(pcie))
-+              enter_l23(pcie);
-+      /* Assert fundamental reset */
-+      brcm_pcie_perst_set(pcie, 1);
-+      /* Deassert request for L23 in case it was asserted */
-+      WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 0);
-+      /* Turn off SerDes */
-+      WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 1);
-+      /* Shutdown PCIe bridge */
-+      brcm_pcie_bridge_sw_init_set(pcie, 1);
-+}
-+
-+static int brcm_pcie_suspend(struct device *dev)
-+{
-+      struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+
-+      turn_off(pcie);
-+      clk_disable_unprepare(pcie->clk);
-+      pcie->suspended = true;
-+
-+      return 0;
-+}
-+
-+static int brcm_pcie_resume(struct device *dev)
-+{
-+      struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+      void __iomem *base;
-+      int ret;
-+
-+      base = pcie->base;
-+      clk_prepare_enable(pcie->clk);
-+
-+      /* Take bridge out of reset so we can access the SerDes reg */
-+      brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+      /* Turn on SerDes */
-+      WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+      /* Wait for SerDes to be stable */
-+      usleep_range(100, 200);
-+
-+      ret = brcm_pcie_setup(pcie);
-+      if (ret)
-+              return ret;
-+
-+      pcie->suspended = false;
-+
-+      return 0;
-+}
-+
-+static void _brcm_pcie_remove(struct brcm_pcie *pcie)
-+{
-+      turn_off(pcie);
-+      clk_disable_unprepare(pcie->clk);
-+      clk_put(pcie->clk);
-+      brcm_pcie_remove_controller(pcie);
-+}
-+
-+static int brcm_pcie_remove(struct platform_device *pdev)
-+{
-+      struct brcm_pcie *pcie = platform_get_drvdata(pdev);
-+
-+      pci_stop_root_bus(pcie->root_bus);
-+      pci_remove_root_bus(pcie->root_bus);
-+      _brcm_pcie_remove(pcie);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id brcm_pcie_match[] = {
-+      { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
-+      { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
-+      { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
-+      { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, brcm_pcie_match);
-+
-+static int brcm_pcie_probe(struct platform_device *pdev)
-+{
-+      struct device_node *dn = pdev->dev.of_node;
-+      const struct of_device_id *of_id;
-+      const struct pcie_cfg_data *data;
-+      int ret;
-+      struct brcm_pcie *pcie;
-+      struct resource *res;
-+      void __iomem *base;
-+      u32 tmp;
-+      struct pci_host_bridge *bridge;
-+      struct pci_bus *child;
-+
-+      bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-+      if (!bridge)
-+              return -ENOMEM;
-+
-+      pcie = pci_host_bridge_priv(bridge);
-+      INIT_LIST_HEAD(&pcie->resources);
-+
-+      of_id = of_match_node(brcm_pcie_match, dn);
-+      if (!of_id) {
-+              dev_err(&pdev->dev, "failed to look up compatible string\n");
-+              return -EINVAL;
-+      }
-+
-+      if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
-+              dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
-+              return -EINVAL;
-+      }
-+
-+      data = of_id->data;
-+      pcie->reg_offsets = data->offsets;
-+      pcie->reg_field_info = data->reg_field_info;
-+      pcie->type = data->type;
-+      pcie->dn = dn;
-+      pcie->dev = &pdev->dev;
-+
-+      /* We use the domain number as our controller number */
-+      pcie->id = of_get_pci_domain_nr(dn);
-+      if (pcie->id < 0)
-+              return pcie->id;
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!res)
-+              return -EINVAL;
-+
-+      base = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(base))
-+              return PTR_ERR(base);
-+
-+      pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-+      if (IS_ERR(pcie->clk)) {
-+              dev_err(&pdev->dev, "could not get clock\n");
-+              pcie->clk = NULL;
-+      }
-+      pcie->base = base;
-+
-+      ret = of_pci_get_max_link_speed(dn);
-+      pcie->gen = (ret < 0) ? 0 : ret;
-+
-+      pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
-+
-+      ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
-+      if (ret == 0)
-+              /* keep going, as we don't use this intr yet */
-+              dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
-+      else
-+              pcie->irq = ret;
-+
-+      ret = brcm_pcie_parse_request_of_pci_ranges(pcie);
-+      if (ret)
-+              return ret;
-+
-+      ret = clk_prepare_enable(pcie->clk);
-+      if (ret) {
-+              dev_err(&pdev->dev, "could not enable clock\n");
-+              return ret;
-+      }
-+
-+      ret = brcm_pcie_add_controller(pcie);
-+      if (ret)
-+              return ret;
-+
-+      ret = brcm_pcie_setup(pcie);
-+      if (ret)
-+              goto fail;
-+
-+      list_splice_init(&pcie->resources, &bridge->windows);
-+      bridge->dev.parent = &pdev->dev;
-+      bridge->busnr = 0;
-+      bridge->ops = &brcm_pcie_ops;
-+      bridge->sysdata = pcie;
-+      bridge->map_irq = of_irq_parse_and_map_pci;
-+      bridge->swizzle_irq = pci_common_swizzle;
-+
-+      ret = pci_scan_root_bus_bridge(bridge);
-+      if (ret < 0) {
-+              dev_err(pcie->dev, "Scanning root bridge failed\n");
-+              goto fail;
-+      }
-+
-+      pci_assign_unassigned_bus_resources(bridge->bus);
-+      list_for_each_entry(child, &bridge->bus->children, node)
-+              pcie_bus_configure_settings(child);
-+      pci_bus_add_devices(bridge->bus);
-+      platform_set_drvdata(pdev, pcie);
-+      pcie->root_bus = bridge->bus;
-+
-+      return 0;
-+
-+fail:
-+      _brcm_pcie_remove(pcie);
-+      return ret;
-+}
-+
-+static const struct dev_pm_ops brcm_pcie_pm_ops = {
-+      .suspend_noirq = brcm_pcie_suspend,
-+      .resume_noirq = brcm_pcie_resume,
-+};
-+
-+static struct platform_driver brcm_pcie_driver = {
-+      .probe = brcm_pcie_probe,
-+      .remove = brcm_pcie_remove,
-+      .driver = {
-+              .name = "brcm-pcie",
-+              .owner = THIS_MODULE,
-+              .of_match_table = brcm_pcie_match,
-+              .pm = &brcm_pcie_pm_ops,
-+      },
-+};
-+
-+module_platform_driver(brcm_pcie_driver);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
-+MODULE_AUTHOR("Broadcom");
---- /dev/null
-+++ b/include/soc/brcmstb/memory_api.h
-@@ -0,0 +1,25 @@
-+#ifndef __MEMORY_API_H
-+#define __MEMORY_API_H
-+
-+/*
-+ * Bus Interface Unit control register setup, must happen early during boot,
-+ * before SMP is brought up, called by machine entry point.
-+ */
-+void brcmstb_biuctrl_init(void);
-+
-+#ifdef CONFIG_SOC_BRCMSTB
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa);
-+u64 brcmstb_memory_memc_size(int memc);
-+#else
-+static inline int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+      return -EINVAL;
-+}
-+
-+static inline u64 brcmstb_memory_memc_size(int memc)
-+{
-+      return -1;
-+}
-+#endif
-+
-+#endif /* __MEMORY_API_H */
diff --git a/target/linux/bcm27xx/patches-5.4/950-0206-PCI-brcmstb-Add-dma-range-mapping-for-inbound-traffi.patch b/target/linux/bcm27xx/patches-5.4/950-0206-PCI-brcmstb-Add-dma-range-mapping-for-inbound-traffi.patch
deleted file mode 100644 (file)
index 329b6e2..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-From d45590eb858ac7a2578d477791881ba7ffb1e615 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add dma-range mapping for inbound
- traffic
-
-The Broadcom STB PCIe host controller is intimately related to the
-memory subsystem.  This close relationship adds complexity to how cpu
-system memory is mapped to PCIe memory.  Ideally, this mapping is an
-identity mapping, or an identity mapping off by a constant.  Not so in
-this case.
-
-Consider the Broadcom reference board BCM97445LCC_4X8 which has 6 GB
-of system memory.  Here is how the PCIe controller maps the
-system memory to PCIe memory:
-
-  memc0-a@[        0....3fffffff] <=> pci@[        0....3fffffff]
-  memc0-b@[100000000...13fffffff] <=> pci@[ 40000000....7fffffff]
-  memc1-a@[ 40000000....7fffffff] <=> pci@[ 80000000....bfffffff]
-  memc1-b@[300000000...33fffffff] <=> pci@[ c0000000....ffffffff]
-  memc2-a@[ 80000000....bfffffff] <=> pci@[100000000...13fffffff]
-  memc2-b@[c00000000...c3fffffff] <=> pci@[140000000...17fffffff]
-
-Although there are some "gaps" that can be added between the
-individual mappings by software, the permutation of memory regions for
-the most part is fixed by HW.  The solution of having something close
-to an identity mapping is not possible.
-
-The idea behind this HW design is that the same PCIe module can
-act as an RC or EP, and if it acts as an EP it concatenates all
-of system memory into a BAR so anything can be accessed.  Unfortunately,
-when the PCIe block is in the role of an RC it also presents this
-"BAR" to downstream PCIe devices, rather than offering an identity map
-between its system memory and PCIe space.
-
-Suppose that an endpoint driver allocs some DMA memory.  Suppose this
-memory is located at 0x6000_0000, which is in the middle of memc1-a.
-The driver wants a dma_addr_t value that it can pass on to the EP to
-use.  Without doing any custom mapping, the EP will use this value for
-DMA: the driver will get a dma_addr_t equal to 0x6000_0000.  But this
-won't work; the device needs a dma_addr_t that reflects the PCIe space
-address, namely 0xa000_0000.
-
-So, essentially the solution to this problem must modify the
-dma_addr_t returned by the DMA routines routines.  There are two
-ways (I know of) of doing this:
-
-(a) overriding/redefining the dma_to_phys() and phys_to_dma() calls
-that are used by the dma_ops routines.  This is the approach of
-
-       arch/mips/cavium-octeon/dma-octeon.c
-
-In ARM and ARM64 these two routines are defiend in asm/dma-mapping.h
-as static inline functions.
-
-(b) Subscribe to a notifier that notifies when a device is added to a
-bus.  When this happens, set_dma_ops() can be called for the device.
-This method is mentioned in:
-
-    http://lxr.free-electrons.com/source/drivers/of/platform.c?v=3.16#L152
-
-where it says as a comment
-
-    "In case if platform code need to use own special DMA
-    configuration, it can use Platform bus notifier and
-    handle BUS_NOTIFY_ADD_DEVICE event to fix up DMA
-    configuration."
-
-Solution (b) is what this commit does.  It uses its own set of
-dma_ops which are wrappers around the arch_dma_ops.  The
-wrappers translate the dma addresses before/after invoking
-the arch_dma_ops, as appropriate.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/pcie-brcmstb.c | 420 +++++++++++++++++++++++++-
- 1 file changed, 411 insertions(+), 9 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -4,6 +4,7 @@
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-+#include <linux/dma-mapping.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
-@@ -319,11 +320,307 @@ static struct pci_ops brcm_pcie_ops = {
-       ((val & ~reg##_##field##_MASK) | \
-        (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-+static const struct dma_map_ops *arch_dma_ops;
-+static const struct dma_map_ops *brcm_dma_ops_ptr;
-+static struct of_pci_range *dma_ranges;
-+static int num_dma_ranges;
-+
- static phys_addr_t scb_size[BRCM_MAX_SCB];
- static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-+static dma_addr_t brcm_to_pci(dma_addr_t addr)
-+{
-+      struct of_pci_range *p;
-+
-+      if (!num_dma_ranges)
-+              return addr;
-+
-+      for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+              if (addr >= p->cpu_addr && addr < (p->cpu_addr + p->size))
-+                      return addr - p->cpu_addr + p->pci_addr;
-+
-+      return addr;
-+}
-+
-+static dma_addr_t brcm_to_cpu(dma_addr_t addr)
-+{
-+      struct of_pci_range *p;
-+
-+      if (!num_dma_ranges)
-+              return addr;
-+
-+      for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+              if (addr >= p->pci_addr && addr < (p->pci_addr + p->size))
-+                      return addr - p->pci_addr + p->cpu_addr;
-+
-+      return addr;
-+}
-+
-+static void *brcm_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-+                      gfp_t gfp, unsigned long attrs)
-+{
-+      void *ret;
-+
-+      ret = arch_dma_ops->alloc(dev, size, handle, gfp, attrs);
-+      if (ret)
-+              *handle = brcm_to_pci(*handle);
-+      return ret;
-+}
-+
-+static void brcm_free(struct device *dev, size_t size, void *cpu_addr,
-+                    dma_addr_t handle, unsigned long attrs)
-+{
-+      handle = brcm_to_cpu(handle);
-+      arch_dma_ops->free(dev, size, cpu_addr, handle, attrs);
-+}
-+
-+static int brcm_mmap(struct device *dev, struct vm_area_struct *vma,
-+                   void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+                   unsigned long attrs)
-+{
-+      dma_addr = brcm_to_cpu(dma_addr);
-+      return arch_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-+}
-+
-+static int brcm_get_sgtable(struct device *dev, struct sg_table *sgt,
-+                          void *cpu_addr, dma_addr_t handle, size_t size,
-+                          unsigned long attrs)
-+{
-+      handle = brcm_to_cpu(handle);
-+      return arch_dma_ops->get_sgtable(dev, sgt, cpu_addr, handle, size,
-+                                     attrs);
-+}
-+
-+static dma_addr_t brcm_map_page(struct device *dev, struct page *page,
-+                              unsigned long offset, size_t size,
-+                              enum dma_data_direction dir,
-+                              unsigned long attrs)
-+{
-+      return brcm_to_pci(arch_dma_ops->map_page(dev, page, offset, size,
-+                                                dir, attrs));
-+}
-+
-+static void brcm_unmap_page(struct device *dev, dma_addr_t handle,
-+                          size_t size, enum dma_data_direction dir,
-+                          unsigned long attrs)
-+{
-+      handle = brcm_to_cpu(handle);
-+      arch_dma_ops->unmap_page(dev, handle, size, dir, attrs);
-+}
-+
-+static int brcm_map_sg(struct device *dev, struct scatterlist *sgl,
-+                     int nents, enum dma_data_direction dir,
-+                     unsigned long attrs)
-+{
-+      int i, j;
-+      struct scatterlist *sg;
-+
-+      for_each_sg(sgl, sg, nents, i) {
-+#ifdef CONFIG_NEED_SG_DMA_LENGTH
-+              sg->dma_length = sg->length;
-+#endif
-+              sg->dma_address =
-+                      brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
-+                                                 sg->length, dir, attrs);
-+              if (dma_mapping_error(dev, sg->dma_address))
-+                      goto bad_mapping;
-+      }
-+      return nents;
-+
-+bad_mapping:
-+      for_each_sg(sgl, sg, i, j)
-+              brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+                                           sg_dma_len(sg), dir, attrs);
-+      return 0;
-+}
-+
-+static void brcm_unmap_sg(struct device *dev,
-+                        struct scatterlist *sgl, int nents,
-+                        enum dma_data_direction dir,
-+                        unsigned long attrs)
-+{
-+      int i;
-+      struct scatterlist *sg;
-+
-+      for_each_sg(sgl, sg, nents, i)
-+              brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+                                           sg_dma_len(sg), dir, attrs);
-+}
-+
-+static void brcm_sync_single_for_cpu(struct device *dev,
-+                                   dma_addr_t handle, size_t size,
-+                                   enum dma_data_direction dir)
-+{
-+      handle = brcm_to_cpu(handle);
-+      arch_dma_ops->sync_single_for_cpu(dev, handle, size, dir);
-+}
-+
-+static void brcm_sync_single_for_device(struct device *dev,
-+                                      dma_addr_t handle, size_t size,
-+                                      enum dma_data_direction dir)
-+{
-+      handle = brcm_to_cpu(handle);
-+      arch_dma_ops->sync_single_for_device(dev, handle, size, dir);
-+}
-+
-+static dma_addr_t brcm_map_resource(struct device *dev, phys_addr_t phys,
-+                                  size_t size,
-+                                  enum dma_data_direction dir,
-+                                  unsigned long attrs)
-+{
-+      if (arch_dma_ops->map_resource)
-+              return brcm_to_pci(arch_dma_ops->map_resource
-+                                 (dev, phys, size, dir, attrs));
-+      return brcm_to_pci((dma_addr_t)phys);
-+}
-+
-+static void brcm_unmap_resource(struct device *dev, dma_addr_t handle,
-+                              size_t size, enum dma_data_direction dir,
-+                              unsigned long attrs)
-+{
-+      if (arch_dma_ops->unmap_resource)
-+              arch_dma_ops->unmap_resource(dev, brcm_to_cpu(handle), size,
-+                                           dir, attrs);
-+}
-+
-+void brcm_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
-+                        int nents, enum dma_data_direction dir)
-+{
-+      struct scatterlist *sg;
-+      int i;
-+
-+      for_each_sg(sgl, sg, nents, i)
-+              brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
-+                                                    sg->length, dir);
-+}
-+
-+void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-+                           int nents, enum dma_data_direction dir)
-+{
-+      struct scatterlist *sg;
-+      int i;
-+
-+      for_each_sg(sgl, sg, nents, i)
-+              brcm_dma_ops_ptr->sync_single_for_device(dev,
-+                                                       sg_dma_address(sg),
-+                                                       sg->length, dir);
-+}
-+
-+static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+      return arch_dma_ops->mapping_error(dev, dma_addr);
-+}
-+
-+static int brcm_dma_supported(struct device *dev, u64 mask)
-+{
-+      if (num_dma_ranges) {
-+              /*
-+               * It is our translated addresses that the EP will "see", so
-+               * we check all of the ranges for the largest possible value.
-+               */
-+              int i;
-+
-+              for (i = 0; i < num_dma_ranges; i++)
-+                      if (dma_ranges[i].pci_addr + dma_ranges[i].size - 1
-+                          > mask)
-+                              return 0;
-+              return 1;
-+      }
-+
-+      return arch_dma_ops->dma_supported(dev, mask);
-+}
-+
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+u64 brcm_get_required_mask)(struct device *dev)
-+{
-+      return arch_dma_ops->get_required_mask(dev);
-+}
-+#endif
-+
-+static const struct dma_map_ops brcm_dma_ops = {
-+      .alloc                  = brcm_alloc,
-+      .free                   = brcm_free,
-+      .mmap                   = brcm_mmap,
-+      .get_sgtable            = brcm_get_sgtable,
-+      .map_page               = brcm_map_page,
-+      .unmap_page             = brcm_unmap_page,
-+      .map_sg                 = brcm_map_sg,
-+      .unmap_sg               = brcm_unmap_sg,
-+      .map_resource           = brcm_map_resource,
-+      .unmap_resource         = brcm_unmap_resource,
-+      .sync_single_for_cpu    = brcm_sync_single_for_cpu,
-+      .sync_single_for_device = brcm_sync_single_for_device,
-+      .sync_sg_for_cpu        = brcm_sync_sg_for_cpu,
-+      .sync_sg_for_device     = brcm_sync_sg_for_device,
-+      .mapping_error          = brcm_mapping_error,
-+      .dma_supported          = brcm_dma_supported,
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+      .get_required_mask      = brcm_get_required_mask,
-+#endif
-+};
-+
-+static void brcm_set_dma_ops(struct device *dev)
-+{
-+      int ret;
-+
-+      if (IS_ENABLED(CONFIG_ARM64)) {
-+              /*
-+               * We are going to invoke get_dma_ops().  That
-+               * function, at this point in time, invokes
-+               * get_arch_dma_ops(), and for ARM64 that function
-+               * returns a pointer to dummy_dma_ops.  So then we'd
-+               * like to call arch_setup_dma_ops(), but that isn't
-+               * exported.  Instead, we call of_dma_configure(),
-+               * which is exported, and this calls
-+               * arch_setup_dma_ops().  Once we do this the call to
-+               * get_dma_ops() will work properly because
-+               * dev->dma_ops will be set.
-+               */
-+              ret = of_dma_configure(dev, dev->of_node, true);
-+              if (ret) {
-+                      dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+                      return;
-+              }
-+      }
-+
-+      arch_dma_ops = get_dma_ops(dev);
-+      if (!arch_dma_ops) {
-+              dev_err(dev, "failed to get arch_dma_ops\n");
-+              return;
-+      }
-+
-+      set_dma_ops(dev, &brcm_dma_ops);
-+}
-+
-+static int brcmstb_platform_notifier(struct notifier_block *nb,
-+                                   unsigned long event, void *__dev)
-+{
-+      struct device *dev = __dev;
-+
-+      brcm_dma_ops_ptr = &brcm_dma_ops;
-+      if (event != BUS_NOTIFY_ADD_DEVICE)
-+              return NOTIFY_DONE;
-+
-+      brcm_set_dma_ops(dev);
-+      return NOTIFY_OK;
-+}
-+
-+static struct notifier_block brcmstb_platform_nb = {
-+      .notifier_call = brcmstb_platform_notifier,
-+};
-+
-+static int brcm_register_notifier(void)
-+{
-+      return bus_register_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
-+static int brcm_unregister_notifier(void)
-+{
-+      return bus_unregister_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
- static u32 rd_fld(void __iomem *p, u32 mask, int shift)
- {
-       return (bcm_readl(p) & mask) >> shift;
-@@ -597,9 +894,71 @@ static inline void brcm_pcie_perst_set(s
-               WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
- }
-+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-+                                   struct device_node *node)
-+{
-+      const int na = 3, ns = 2;
-+      int rlen;
-+
-+      parser->node = node;
-+      parser->pna = of_n_addr_cells(node);
-+      parser->np = parser->pna + na + ns;
-+
-+      parser->range = of_get_property(node, "dma-ranges", &rlen);
-+      if (!parser->range)
-+              return -ENOENT;
-+
-+      parser->end = parser->range + rlen / sizeof(__be32);
-+
-+      return 0;
-+}
-+
-+static int brcm_pcie_parse_map_dma_ranges(struct brcm_pcie *pcie)
-+{
-+      int i;
-+      struct of_pci_range_parser parser;
-+      struct device_node *dn = pcie->dn;
-+
-+      /*
-+       * Parse dma-ranges property if present.  If there are multiple
-+       * PCIe controllers, we only have to parse from one of them since
-+       * the others will have an identical mapping.
-+       */
-+      if (!pci_dma_range_parser_init(&parser, dn)) {
-+              unsigned int max_ranges
-+                      = (parser.end - parser.range) / parser.np;
-+
-+              dma_ranges = kcalloc(max_ranges, sizeof(struct of_pci_range),
-+                                   GFP_KERNEL);
-+              if (!dma_ranges)
-+                      return -ENOMEM;
-+
-+              for (i = 0; of_pci_range_parser_one(&parser, dma_ranges + i);
-+                   i++)
-+                      num_dma_ranges++;
-+      }
-+
-+      for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+              u64 size = brcmstb_memory_memc_size(i);
-+
-+              if (size == (u64)-1) {
-+                      dev_err(pcie->dev, "cannot get memc%d size", i);
-+                      return -EINVAL;
-+              } else if (size) {
-+                      scb_size[i] = roundup_pow_of_two_64(size);
-+                      num_memc++;
-+              } else {
-+                      break;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
- static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
- {
-       int i, ret = 0;
-+      struct device *dev = pcie->dev;
-       mutex_lock(&brcm_pcie_lock);
-       if (num_pcie > 0) {
-@@ -607,12 +966,21 @@ static int brcm_pcie_add_controller(stru
-               goto done;
-       }
-+      ret = brcm_register_notifier();
-+      if (ret) {
-+              dev_err(dev, "failed to register pci bus notifier\n");
-+              goto done;
-+      }
-+      ret = brcm_pcie_parse_map_dma_ranges(pcie);
-+      if (ret)
-+              goto done;
-+
-       /* Determine num_memc and their sizes */
-       for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-               u64 size = brcmstb_memory_memc_size(i);
-               if (size == (u64)-1) {
--                      dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+                      dev_err(dev, "cannot get memc%d size\n", i);
-                       ret = -EINVAL;
-                       goto done;
-               } else if (size) {
-@@ -636,8 +1004,16 @@ done:
- static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
- {
-       mutex_lock(&brcm_pcie_lock);
--      if (--num_pcie == 0)
--              num_memc = 0;
-+      if (--num_pcie > 0)
-+              goto out;
-+
-+      if (brcm_unregister_notifier())
-+              dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
-+      kfree(dma_ranges);
-+      dma_ranges = NULL;
-+      num_dma_ranges = 0;
-+      num_memc = 0;
-+out:
-       mutex_unlock(&brcm_pcie_lock);
- }
-@@ -757,6 +1133,38 @@ static int brcm_pcie_setup(struct brcm_p
-        */
-       rc_bar2_offset = 0;
-+      if (dma_ranges) {
-+              /*
-+               * The best-case scenario is to place the inbound
-+               * region in the first 4GB of pci-space, as some
-+               * legacy devices can only address 32bits.
-+               * We would also like to put the MSI under 4GB
-+               * as well, since some devices require a 32bit
-+               * MSI target address.
-+               */
-+              if (total_mem_size <= 0xc0000000ULL &&
-+                  rc_bar2_size <= 0x100000000ULL) {
-+                      rc_bar2_offset = 0;
-+              } else {
-+                      /*
-+                       * The system memory is 4GB or larger so we
-+                       * cannot start the inbound region at location
-+                       * 0 (since we have to allow some space for
-+                       * outbound memory @ 3GB).  So instead we
-+                       * start it at the 1x multiple of its size
-+                       */
-+                      rc_bar2_offset = rc_bar2_size;
-+              }
-+
-+      } else {
-+              /*
-+               * Set simple configuration based on memory sizes
-+               * only.  We always start the viewport at address 0,
-+               * and set the MSI target address accordingly.
-+               */
-+              rc_bar2_offset = 0;
-+      }
-+
-       tmp = lower_32_bits(rc_bar2_offset);
-       tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-                          encode_ibar_size(rc_bar2_size));
-@@ -967,7 +1375,6 @@ static int brcm_pcie_probe(struct platfo
-       struct brcm_pcie *pcie;
-       struct resource *res;
-       void __iomem *base;
--      u32 tmp;
-       struct pci_host_bridge *bridge;
-       struct pci_bus *child;
-@@ -984,11 +1391,6 @@ static int brcm_pcie_probe(struct platfo
-               return -EINVAL;
-       }
--      if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
--              dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
--              return -EINVAL;
--      }
--
-       data = of_id->data;
-       pcie->reg_offsets = data->offsets;
-       pcie->reg_field_info = data->reg_field_info;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0207-PCI-brcmstb-Add-MSI-capability.patch b/target/linux/bcm27xx/patches-5.4/950-0207-PCI-brcmstb-Add-MSI-capability.patch
deleted file mode 100644 (file)
index d2cf8e2..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-From b1619c83208e7b804e2c3547dbf24bb02b3be239 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add MSI capability
-
-This commit adds MSI to the Broadcom STB PCIe host controller. It does
-not add MSIX since that functionality is not in the HW.  The MSI
-controller is physically located within the PCIe block, however, there
-is no reason why the MSI controller could not be moved elsewhere in
-the future.
-
-Since the internal Brcmstb MSI controller is intertwined with the PCIe
-controller, it is not its own platform device but rather part of the
-PCIe platform device.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/pcie-brcmstb.c | 374 ++++++++++++++++++++++++--
- 1 file changed, 353 insertions(+), 21 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (C) 2009 - 2017 Broadcom */
-+#include <linux/bitops.h>
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-@@ -9,11 +10,13 @@
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
-+#include <linux/irqchip/chained_irq.h>
- #include <linux/irqdomain.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/log2.h>
- #include <linux/module.h>
-+#include <linux/msi.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/of_pci.h>
-@@ -47,6 +50,9 @@
- #define PCIE_MISC_RC_BAR2_CONFIG_LO                   0x4034
- #define PCIE_MISC_RC_BAR2_CONFIG_HI                   0x4038
- #define PCIE_MISC_RC_BAR3_CONFIG_LO                   0x403c
-+#define PCIE_MISC_MSI_BAR_CONFIG_LO                   0x4044
-+#define PCIE_MISC_MSI_BAR_CONFIG_HI                   0x4048
-+#define PCIE_MISC_MSI_DATA_CONFIG                     0x404c
- #define PCIE_MISC_PCIE_CTRL                           0x4064
- #define PCIE_MISC_PCIE_STATUS                         0x4068
- #define PCIE_MISC_REVISION                            0x406c
-@@ -55,6 +61,7 @@
- #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI                0x4084
- #define PCIE_MISC_HARD_PCIE_HARD_DEBUG                        0x4204
- #define PCIE_INTR2_CPU_BASE                           0x4300
-+#define PCIE_MSI_INTR2_BASE                           0x4500
- /*
-  * Broadcom Settop Box PCIe Register Field shift and mask info. The
-@@ -115,6 +122,8 @@
- #define BRCM_NUM_PCIE_OUT_WINS                0x4
- #define BRCM_MAX_SCB                  0x4
-+#define BRCM_INT_PCI_MSI_NR           32
-+#define BRCM_PCIE_HW_REV_33           0x0303
- #define BRCM_MSI_TARGET_ADDR_LT_4GB   0x0fffffffcULL
- #define BRCM_MSI_TARGET_ADDR_GT_4GB   0xffffffffcULL
-@@ -203,6 +212,33 @@ struct brcm_window {
-       dma_addr_t size;
- };
-+struct brcm_msi {
-+      struct device           *dev;
-+      void __iomem            *base;
-+      struct device_node      *dn;
-+      struct irq_domain       *msi_domain;
-+      struct irq_domain       *inner_domain;
-+      struct mutex            lock; /* guards the alloc/free operations */
-+      u64                     target_addr;
-+      int                     irq;
-+
-+      /* intr_base is the base pointer for interrupt status/set/clr regs */
-+      void __iomem            *intr_base;
-+
-+      /* intr_legacy_mask indicates how many bits are MSI interrupts */
-+      u32                     intr_legacy_mask;
-+
-+      /*
-+       * intr_legacy_offset indicates bit position of MSI_01. It is
-+       * to map the register bit position to a hwirq that starts at 0.
-+       */
-+      u32                     intr_legacy_offset;
-+
-+      /* used indicates which MSI interrupts have been alloc'd */
-+      unsigned long           used;
-+      unsigned int            rev;
-+};
-+
- /* Internal PCIe Host Controller Information.*/
- struct brcm_pcie {
-       struct device           *dev;
-@@ -217,7 +253,10 @@ struct brcm_pcie {
-       int                     num_out_wins;
-       bool                    ssc;
-       int                     gen;
-+      u64                     msi_target_addr;
-       struct brcm_window      out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+      struct brcm_msi         *msi;
-+      bool                    msi_internal;
-       unsigned int            rev;
-       const int               *reg_offsets;
-       const int               *reg_field_info;
-@@ -225,9 +264,9 @@ struct brcm_pcie {
- };
- struct pcie_cfg_data {
--      const int *reg_field_info;
--      const int *offsets;
--      const enum pcie_type type;
-+      const int               *reg_field_info;
-+      const int               *offsets;
-+      const enum pcie_type    type;
- };
- static const int pcie_reg_field_info[] = {
-@@ -828,6 +867,267 @@ static void brcm_pcie_set_outbound_win(s
-       }
- }
-+static struct irq_chip brcm_msi_irq_chip = {
-+      .name = "Brcm_MSI",
-+      .irq_mask = pci_msi_mask_irq,
-+      .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+static struct msi_domain_info brcm_msi_domain_info = {
-+      .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-+                 MSI_FLAG_PCI_MSIX),
-+      .chip   = &brcm_msi_irq_chip,
-+};
-+
-+static void brcm_pcie_msi_isr(struct irq_desc *desc)
-+{
-+      struct irq_chip *chip = irq_desc_get_chip(desc);
-+      struct brcm_msi *msi;
-+      unsigned long status, virq;
-+      u32 mask, bit, hwirq;
-+      struct device *dev;
-+
-+      chained_irq_enter(chip, desc);
-+      msi = irq_desc_get_handler_data(desc);
-+      mask = msi->intr_legacy_mask;
-+      dev = msi->dev;
-+
-+      while ((status = bcm_readl(msi->intr_base + STATUS) & mask)) {
-+              for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
-+                      /* clear the interrupt */
-+                      bcm_writel(1 << bit, msi->intr_base + CLR);
-+
-+                      /* Account for legacy interrupt offset */
-+                      hwirq = bit - msi->intr_legacy_offset;
-+
-+                      virq = irq_find_mapping(msi->inner_domain, hwirq);
-+                      if (virq) {
-+                              if (msi->used & (1 << hwirq))
-+                                      generic_handle_irq(virq);
-+                              else
-+                                      dev_info(dev, "unhandled MSI %d\n",
-+                                               hwirq);
-+                      } else {
-+                              /* Unknown MSI, just clear it */
-+                              dev_dbg(dev, "unexpected MSI\n");
-+                      }
-+              }
-+      }
-+      chained_irq_exit(chip, desc);
-+}
-+
-+static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+{
-+      struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
-+      u32 temp;
-+
-+      msg->address_lo = lower_32_bits(msi->target_addr);
-+      msg->address_hi = upper_32_bits(msi->target_addr);
-+      temp = bcm_readl(msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+      msg->data = ((temp >> 16) & (temp & 0xffff)) | data->hwirq;
-+}
-+
-+static int brcm_msi_set_affinity(struct irq_data *irq_data,
-+                               const struct cpumask *mask, bool force)
-+{
-+      return -EINVAL;
-+}
-+
-+static struct irq_chip brcm_msi_bottom_irq_chip = {
-+      .name                   = "Brcm_MSI",
-+      .irq_compose_msi_msg    = brcm_compose_msi_msg,
-+      .irq_set_affinity       = brcm_msi_set_affinity,
-+};
-+
-+static int brcm_msi_alloc(struct brcm_msi *msi)
-+{
-+      int bit, hwirq;
-+
-+      mutex_lock(&msi->lock);
-+      bit = ~msi->used ? ffz(msi->used) : -1;
-+
-+      if (bit >= 0 && bit < BRCM_INT_PCI_MSI_NR) {
-+              msi->used |= (1 << bit);
-+              hwirq = bit - msi->intr_legacy_offset;
-+      } else {
-+              hwirq = -ENOSPC;
-+      }
-+
-+      mutex_unlock(&msi->lock);
-+      return hwirq;
-+}
-+
-+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
-+{
-+      mutex_lock(&msi->lock);
-+      msi->used &= ~(1 << (hwirq + msi->intr_legacy_offset));
-+      mutex_unlock(&msi->lock);
-+}
-+
-+static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
-+                               unsigned int nr_irqs, void *args)
-+{
-+      struct brcm_msi *msi = domain->host_data;
-+      int hwirq;
-+
-+      hwirq = brcm_msi_alloc(msi);
-+
-+      if (hwirq < 0)
-+              return hwirq;
-+
-+      irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
-+                          &brcm_msi_bottom_irq_chip, domain->host_data,
-+                          handle_simple_irq, NULL, NULL);
-+      return 0;
-+}
-+
-+static void brcm_irq_domain_free(struct irq_domain *domain,
-+                               unsigned int virq, unsigned int nr_irqs)
-+{
-+      struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-+      struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
-+
-+      brcm_msi_free(msi, d->hwirq);
-+}
-+
-+static void brcm_msi_set_regs(struct brcm_msi *msi)
-+{
-+      u32 data_val, msi_lo, msi_hi;
-+
-+      if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+              /*
-+               * ffe0 -- least sig 5 bits are 0 indicating 32 msgs
-+               * 6540 -- this is our arbitrary unique data value
-+               */
-+              data_val = 0xffe06540;
-+      } else {
-+              /*
-+               * fff8 -- least sig 3 bits are 0 indicating 8 msgs
-+               * 6540 -- this is our arbitrary unique data value
-+               */
-+              data_val = 0xfff86540;
-+      }
-+
-+      /*
-+       * Make sure we are not masking MSIs.  Note that MSIs can be masked,
-+       * but that occurs on the PCIe EP device
-+       */
-+      bcm_writel(0xffffffff & msi->intr_legacy_mask,
-+                 msi->intr_base + MASK_CLR);
-+
-+      msi_lo = lower_32_bits(msi->target_addr);
-+      msi_hi = upper_32_bits(msi->target_addr);
-+      /*
-+       * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
-+       * enable, which we set to 1.
-+       */
-+      bcm_writel(msi_lo | 1, msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
-+      bcm_writel(msi_hi, msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
-+      bcm_writel(data_val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+}
-+
-+static const struct irq_domain_ops msi_domain_ops = {
-+      .alloc  = brcm_irq_domain_alloc,
-+      .free   = brcm_irq_domain_free,
-+};
-+
-+static int brcm_allocate_domains(struct brcm_msi *msi)
-+{
-+      struct fwnode_handle *fwnode = of_node_to_fwnode(msi->dn);
-+      struct device *dev = msi->dev;
-+
-+      msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
-+                                                &msi_domain_ops, msi);
-+      if (!msi->inner_domain) {
-+              dev_err(dev, "failed to create IRQ domain\n");
-+              return -ENOMEM;
-+      }
-+
-+      msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-+                                                  &brcm_msi_domain_info,
-+                                                  msi->inner_domain);
-+      if (!msi->msi_domain) {
-+              dev_err(dev, "failed to create MSI domain\n");
-+              irq_domain_remove(msi->inner_domain);
-+              return -ENOMEM;
-+      }
-+
-+      return 0;
-+}
-+
-+static void brcm_free_domains(struct brcm_msi *msi)
-+{
-+      irq_domain_remove(msi->msi_domain);
-+      irq_domain_remove(msi->inner_domain);
-+}
-+
-+static void brcm_msi_remove(struct brcm_pcie *pcie)
-+{
-+      struct brcm_msi *msi = pcie->msi;
-+
-+      if (!msi)
-+              return;
-+      irq_set_chained_handler(msi->irq, NULL);
-+      irq_set_handler_data(msi->irq, NULL);
-+      brcm_free_domains(msi);
-+}
-+
-+static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
-+{
-+      struct brcm_msi *msi;
-+      int irq, ret;
-+      struct device *dev = pcie->dev;
-+
-+      irq = irq_of_parse_and_map(dev->of_node, 1);
-+      if (irq <= 0) {
-+              dev_err(dev, "cannot map msi intr\n");
-+              return -ENODEV;
-+      }
-+
-+      msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
-+      if (!msi)
-+              return -ENOMEM;
-+
-+      msi->dev = dev;
-+      msi->base = pcie->base;
-+      msi->rev =  pcie->rev;
-+      msi->dn = pcie->dn;
-+      msi->target_addr = pcie->msi_target_addr;
-+      msi->irq = irq;
-+
-+      ret = brcm_allocate_domains(msi);
-+      if (ret)
-+              return ret;
-+
-+      irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
-+
-+      if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+              msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
-+              /*
-+               * This version of PCIe hw has only 32 intr bits
-+               * starting at bit position 0.
-+               */
-+              msi->intr_legacy_mask = 0xffffffff;
-+              msi->intr_legacy_offset = 0x0;
-+              msi->used = 0x0;
-+
-+      } else {
-+              msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
-+              /*
-+               * This version of PCIe hw has only 8 intr bits starting
-+               * at bit position 24.
-+               */
-+              msi->intr_legacy_mask = 0xff000000;
-+              msi->intr_legacy_offset = 24;
-+              msi->used = 0x00ffffff;
-+      }
-+
-+      brcm_msi_set_regs(msi);
-+      pcie->msi = msi;
-+
-+      return 0;
-+}
-+
- /* Configuration space read/write support */
- static int cfg_index(int busnr, int devfn, int reg)
- {
-@@ -1072,6 +1372,7 @@ static int brcm_pcie_setup(struct brcm_p
-       u16 nlw, cls, lnksta;
-       bool ssc_good = false;
-       struct device *dev = pcie->dev;
-+      u64 msi_target_addr;
-       /* Reset the bridge */
-       brcm_pcie_bridge_sw_init_set(pcie, 1);
-@@ -1116,27 +1417,24 @@ static int brcm_pcie_setup(struct brcm_p
-        * The PCIe host controller by design must set the inbound
-        * viewport to be a contiguous arrangement of all of the
-        * system's memory.  In addition, its size mut be a power of
--       * two.  To further complicate matters, the viewport must
--       * start on a pcie-address that is aligned on a multiple of its
--       * size.  If a portion of the viewport does not represent
--       * system memory -- e.g. 3GB of memory requires a 4GB viewport
--       * -- we can map the outbound memory in or after 3GB and even
--       * though the viewport will overlap the outbound memory the
--       * controller will know to send outbound memory downstream and
--       * everything else upstream.
-+       * two.  Further, the MSI target address must NOT be placed
-+       * inside this region, as the decoding logic will consider its
-+       * address to be inbound memory traffic.  To further
-+       * complicate matters, the viewport must start on a
-+       * pcie-address that is aligned on a multiple of its size.
-+       * If a portion of the viewport does not represent system
-+       * memory -- e.g. 3GB of memory requires a 4GB viewport --
-+       * we can map the outbound memory in or after 3GB and even
-+       * though the viewport will overlap the outbound memory
-+       * the controller will know to send outbound memory downstream
-+       * and everything else upstream.
-        */
-       rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
--      /*
--       * Set simple configuration based on memory sizes
--       * only.  We always start the viewport at address 0.
--       */
--      rc_bar2_offset = 0;
--
-       if (dma_ranges) {
-               /*
-                * The best-case scenario is to place the inbound
--               * region in the first 4GB of pci-space, as some
-+               * region in the first 4GB of pcie-space, as some
-                * legacy devices can only address 32bits.
-                * We would also like to put the MSI under 4GB
-                * as well, since some devices require a 32bit
-@@ -1145,6 +1443,14 @@ static int brcm_pcie_setup(struct brcm_p
-               if (total_mem_size <= 0xc0000000ULL &&
-                   rc_bar2_size <= 0x100000000ULL) {
-                       rc_bar2_offset = 0;
-+                      /* If the viewport is less then 4GB we can fit
-+                       * the MSI target address under 4GB. Otherwise
-+                       * put it right below 64GB.
-+                       */
-+                      msi_target_addr =
-+                              (rc_bar2_size == 0x100000000ULL)
-+                              ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+                              : BRCM_MSI_TARGET_ADDR_LT_4GB;
-               } else {
-                       /*
-                        * The system memory is 4GB or larger so we
-@@ -1154,8 +1460,12 @@ static int brcm_pcie_setup(struct brcm_p
-                        * start it at the 1x multiple of its size
-                        */
-                       rc_bar2_offset = rc_bar2_size;
--              }
-+                      /* Since we are starting the viewport at 4GB or
-+                       * higher, put the MSI target address below 4GB
-+                       */
-+                      msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+              }
-       } else {
-               /*
-                * Set simple configuration based on memory sizes
-@@ -1163,7 +1473,12 @@ static int brcm_pcie_setup(struct brcm_p
-                * and set the MSI target address accordingly.
-                */
-               rc_bar2_offset = 0;
-+
-+              msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
-+                      ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+                      : BRCM_MSI_TARGET_ADDR_LT_4GB;
-       }
-+      pcie->msi_target_addr = msi_target_addr;
-       tmp = lower_32_bits(rc_bar2_offset);
-       tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-@@ -1333,6 +1648,9 @@ static int brcm_pcie_resume(struct devic
-       if (ret)
-               return ret;
-+      if (pcie->msi && pcie->msi_internal)
-+              brcm_msi_set_regs(pcie->msi);
-+
-       pcie->suspended = false;
-       return 0;
-@@ -1340,6 +1658,7 @@ static int brcm_pcie_resume(struct devic
- static void _brcm_pcie_remove(struct brcm_pcie *pcie)
- {
-+      brcm_msi_remove(pcie);
-       turn_off(pcie);
-       clk_disable_unprepare(pcie->clk);
-       clk_put(pcie->clk);
-@@ -1368,7 +1687,7 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
- static int brcm_pcie_probe(struct platform_device *pdev)
- {
--      struct device_node *dn = pdev->dev.of_node;
-+      struct device_node *dn = pdev->dev.of_node, *msi_dn;
-       const struct of_device_id *of_id;
-       const struct pcie_cfg_data *data;
-       int ret;
-@@ -1448,6 +1767,20 @@ static int brcm_pcie_probe(struct platfo
-       if (ret)
-               goto fail;
-+      msi_dn = of_parse_phandle(pcie->dn, "msi-parent", 0);
-+      /* Use the internal MSI if no msi-parent property */
-+      if (!msi_dn)
-+              msi_dn = pcie->dn;
-+
-+      if (pci_msi_enabled() && msi_dn == pcie->dn) {
-+              ret = brcm_pcie_enable_msi(pcie);
-+              if (ret)
-+                      dev_err(pcie->dev,
-+                              "probe of internal MSI failed: %d)", ret);
-+              else
-+                      pcie->msi_internal = true;
-+      }
-+
-       list_splice_init(&pcie->resources, &bridge->windows);
-       bridge->dev.parent = &pdev->dev;
-       bridge->busnr = 0;
-@@ -1470,7 +1803,6 @@ static int brcm_pcie_probe(struct platfo
-       pcie->root_bus = bridge->bus;
-       return 0;
--
- fail:
-       _brcm_pcie_remove(pcie);
-       return ret;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0209-pcie-brcmstb-Changes-for-BCM2711.patch b/target/linux/bcm27xx/patches-5.4/950-0209-pcie-brcmstb-Changes-for-BCM2711.patch
deleted file mode 100644 (file)
index edeab95..0000000
+++ /dev/null
@@ -1,1428 +0,0 @@
-From 1dab5ded41ed07adc12f26e529aa64209a7c44b6 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] pcie-brcmstb: Changes for BCM2711
-
-The initial brcmstb PCIe driver - originally taken from the V3(?)
-patch set - has been modified significantly for the BCM2711.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/dma/bcm2835-dma.c                    | 107 ++++
- drivers/pci/controller/Makefile              |   4 +
- drivers/pci/controller/pcie-brcmstb-bounce.c | 558 +++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb-bounce.h |  32 ++
- drivers/pci/controller/pcie-brcmstb.c        | 245 ++++----
- drivers/soc/bcm/brcmstb/Makefile             |   2 +-
- drivers/soc/bcm/brcmstb/memory.c             | 158 ++++++
- 7 files changed, 991 insertions(+), 115 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.c
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.h
- create mode 100644 drivers/soc/bcm/brcmstb/memory.c
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -64,6 +64,17 @@ struct bcm2835_dma_cb {
-       uint32_t pad[2];
- };
-+struct bcm2838_dma40_scb {
-+      uint32_t ti;
-+      uint32_t src;
-+      uint32_t srci;
-+      uint32_t dst;
-+      uint32_t dsti;
-+      uint32_t len;
-+      uint32_t next_cb;
-+      uint32_t rsvd;
-+};
-+
- struct bcm2835_cb_entry {
-       struct bcm2835_dma_cb *cb;
-       dma_addr_t paddr;
-@@ -180,6 +191,45 @@ struct bcm2835_desc {
- #define MAX_DMA_LEN SZ_1G
- #define MAX_LITE_DMA_LEN (SZ_64K - 4)
-+/* 40-bit DMA support */
-+#define BCM2838_DMA40_CS      0x00
-+#define BCM2838_DMA40_CB      0x04
-+#define BCM2838_DMA40_DEBUG   0x0c
-+#define BCM2858_DMA40_TI      0x10
-+#define BCM2838_DMA40_SRC     0x14
-+#define BCM2838_DMA40_SRCI    0x18
-+#define BCM2838_DMA40_DEST    0x1c
-+#define BCM2838_DMA40_DESTI   0x20
-+#define BCM2838_DMA40_LEN     0x24
-+#define BCM2838_DMA40_NEXT_CB 0x28
-+#define BCM2838_DMA40_DEBUG2  0x2c
-+
-+#define BCM2838_DMA40_CS_ACTIVE       BIT(0)
-+#define BCM2838_DMA40_CS_END  BIT(1)
-+
-+#define BCM2838_DMA40_CS_QOS(x)       (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_CS_WRITE_WAIT   BIT(28)
-+
-+#define BCM2838_DMA40_BURST_LEN(x)    ((((x) - 1) & 0xf) << 8)
-+#define BCM2838_DMA40_INC             BIT(12)
-+#define BCM2838_DMA40_SIZE_128        (2 << 13)
-+
-+#define BCM2838_DMA40_MEMCPY_QOS \
-+      (BCM2838_DMA40_CS_QOS(0x0) | \
-+       BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
-+       BCM2838_DMA40_CS_WRITE_WAIT)
-+
-+#define BCM2838_DMA40_MEMCPY_XFER_INFO \
-+      (BCM2838_DMA40_SIZE_128 | \
-+       BCM2838_DMA40_INC | \
-+       BCM2838_DMA40_BURST_LEN(16))
-+
-+static void __iomem *memcpy_chan;
-+static struct bcm2838_dma40_scb *memcpy_scb;
-+static dma_addr_t memcpy_scb_dma;
-+DEFINE_SPINLOCK(memcpy_lock);
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
-       /* lite and normal channels have different max frame length */
-@@ -866,6 +916,56 @@ static void bcm2835_dma_free(struct bcm2
-                            DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
-+int bcm2838_dma40_memcpy_init(struct device *dev)
-+{
-+      if (memcpy_scb)
-+              return 0;
-+
-+      memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
-+                                      &memcpy_scb_dma, GFP_KERNEL);
-+
-+      if (!memcpy_scb) {
-+              pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+              return -ENOMEM;
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
-+
-+void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
-+{
-+      struct bcm2838_dma40_scb *scb = memcpy_scb;
-+      unsigned long flags;
-+
-+      if (!scb) {
-+              pr_err("bcm2838_dma40_memcpy not initialised!\n");
-+              return;
-+      }
-+
-+      spin_lock_irqsave(&memcpy_lock, flags);
-+
-+      scb->ti = 0;
-+      scb->src = lower_32_bits(src);
-+      scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+      scb->dst = lower_32_bits(dst);
-+      scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+      scb->len = size;
-+      scb->next_cb = 0;
-+
-+      writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-+      writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+             memcpy_chan + BCM2838_DMA40_CS);
-+      /* Poll for completion */
-+      while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+              cpu_relax();
-+
-+      writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+
-+      spin_unlock_irqrestore(&memcpy_lock, flags);
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-+
- static const struct of_device_id bcm2835_dma_of_match[] = {
-       { .compatible = "brcm,bcm2835-dma", },
-       {},
-@@ -971,6 +1071,13 @@ static int bcm2835_dma_probe(struct plat
-       /* Channel 0 is used by the legacy API */
-       chans_available &= ~BCM2835_DMA_BULK_MASK;
-+      /* We can't use channels 11-13 yet */
-+      chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+
-+      /* Grab channel 14 for the 40-bit DMA memcpy */
-+      chans_available &= ~BIT(14);
-+      memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+
-       /* get irqs for each channel that we support */
-       for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-               /* skip masked out channels */
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -30,6 +30,10 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
-+ifdef CONFIG_ARM
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
-+endif
-+
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y                         += dwc/
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -0,0 +1,558 @@
-+/*
-+ *  This code started out as a version of arch/arm/common/dmabounce.c,
-+ *  modified to cope with highmem pages. Now it has been changed heavily -
-+ *  it now preallocates a large block (currently 4MB) and carves it up
-+ *  sequentially in ring fashion, and DMA is used to copy the data - to the
-+ *  point where very little of the original remains.
-+ *
-+ *  Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ *  Original version by Brad Parker (brad@heeltoe.com)
-+ *  Re-written by Christopher Hoover <ch@murgatroid.com>
-+ *  Made generic by Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ *  Copyright (C) 2002 Hewlett Packard Company.
-+ *  Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ *  This program is free software; you can redistribute it and/or
-+ *  modify it under the terms of the GNU General Public License
-+ *  version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+
-+#include <asm/cacheflush.h>
-+#include <asm/dma-iommu.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+      struct list_head node;
-+
-+      /* original request */
-+      size_t          size;
-+      int             direction;
-+
-+      struct dmabounce_pool *pool;
-+      void            *safe;
-+      dma_addr_t      unsafe_dma_addr;
-+      dma_addr_t      safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+      unsigned long   pages;
-+      void            *virt_addr;
-+      dma_addr_t      dma_addr;
-+      unsigned long   *alloc_map;
-+      unsigned long   alloc_pos;
-+      spinlock_t      lock;
-+      struct device   *dev;
-+      unsigned long   num_pages;
-+#ifdef STATS
-+      size_t          max_size;
-+      unsigned long   num_bufs;
-+      unsigned long   max_bufs;
-+      unsigned long   max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+      struct device *dev;
-+      dma_addr_t threshold;
-+      struct list_head safe_buffers;
-+      struct dmabounce_pool pool;
-+      rwlock_t lock;
-+#ifdef STATS
-+      unsigned long map_count;
-+      unsigned long unmap_count;
-+      unsigned long sync_dev_count;
-+      unsigned long sync_cpu_count;
-+      unsigned long fail_count;
-+      int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+      return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+              device_info->map_count,
-+              device_info->unmap_count,
-+              device_info->sync_dev_count,
-+              device_info->sync_cpu_count,
-+              device_info->fail_count,
-+              device_info->pool.max_size,
-+              device_info->pool.num_bufs,
-+              device_info->pool.max_bufs,
-+              device_info->pool.num_pages * PAGE_SIZE,
-+              device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+                       unsigned long buffer_size)
-+{
-+      int ret = -ENOMEM;
-+      pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+      pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+      if (!pool->alloc_map)
-+              goto err_bitmap;
-+      pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+                                           &pool->dma_addr, GFP_KERNEL);
-+      if (!pool->virt_addr)
-+              goto err_dmabuf;
-+
-+      pool->alloc_pos = 0;
-+      spin_lock_init(&pool->lock);
-+      pool->dev = dev;
-+      pool->num_pages = 0;
-+
-+      DO_STATS(pool->max_size = 0);
-+      DO_STATS(pool->num_bufs = 0);
-+      DO_STATS(pool->max_bufs = 0);
-+      DO_STATS(pool->max_pages = 0);
-+
-+      return  0;
-+
-+err_dmabuf:
-+      bitmap_free(pool->alloc_map);
-+err_bitmap:
-+      return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+      dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+                        pool->dma_addr);
-+
-+      bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+                        dma_addr_t *dmaaddrp)
-+{
-+      unsigned long pages;
-+      unsigned long flags;
-+      unsigned long pos;
-+
-+      pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+      DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+      spin_lock_irqsave(&pool->lock, flags);
-+      pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+                                       pool->alloc_pos, pages, 0);
-+      /* If not found, try from the start */
-+      if (pos >= pool->pages && pool->alloc_pos)
-+              pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+                                               0, pages, 0);
-+
-+      if (pos >= pool->pages) {
-+              spin_unlock_irqrestore(&pool->lock, flags);
-+              return NULL;
-+      }
-+
-+      bitmap_set(pool->alloc_map, pos, pages);
-+      pool->alloc_pos = (pos + pages) % pool->pages;
-+      pool->num_pages += pages;
-+
-+      DO_STATS(pool->num_bufs++);
-+      DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+      DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+      spin_unlock_irqrestore(&pool->lock, flags);
-+
-+      *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+      return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+      unsigned long pages;
-+      unsigned long flags;
-+      unsigned long pos;
-+
-+      pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+      pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+      BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+      spin_lock_irqsave(&pool->lock, flags);
-+      bitmap_clear(pool->alloc_map, pos, pages);
-+      pool->num_pages -= pages;
-+      if (pool->num_pages == 0)
-+              pool->alloc_pos = 0;
-+      DO_STATS(pool->num_bufs--);
-+      spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+                dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+      struct dmabounce_pool *pool = &device_info->pool;
-+      struct device *dev = device_info->dev;
-+      unsigned long flags;
-+
-+      /*
-+       * Although one might expect this to be called in thread context,
-+       * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+       * was previously used to select the appropriate allocation mode,
-+       * but this is unsafe.
-+       */
-+      buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+      if (!buf) {
-+              dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+              return NULL;
-+      }
-+
-+      buf->unsafe_dma_addr = dma_addr;
-+      buf->size = size;
-+      buf->direction = dir;
-+      buf->pool = pool;
-+
-+      buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+      if (!buf->safe) {
-+              dev_warn(dev,
-+                       "%s: could not alloc dma memory (size=%d)\n",
-+                       __func__, size);
-+              kfree(buf);
-+              return NULL;
-+      }
-+
-+      write_lock_irqsave(&device_info->lock, flags);
-+      list_add(&buf->node, &device_info->safe_buffers);
-+      write_unlock_irqrestore(&device_info->lock, flags);
-+
-+      return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+               dma_addr_t safe_dma_addr)
-+{
-+      struct safe_buffer *b, *rb = NULL;
-+      unsigned long flags;
-+
-+      read_lock_irqsave(&device_info->lock, flags);
-+
-+      list_for_each_entry(b, &device_info->safe_buffers, node)
-+              if (b->safe_dma_addr <= safe_dma_addr &&
-+                  b->safe_dma_addr + b->size > safe_dma_addr) {
-+                      rb = b;
-+                      break;
-+              }
-+
-+      read_unlock_irqrestore(&device_info->lock, flags);
-+      return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+               struct safe_buffer *buf)
-+{
-+      unsigned long flags;
-+
-+      write_lock_irqsave(&device_info->lock, flags);
-+      list_del(&buf->node);
-+      write_unlock_irqrestore(&device_info->lock, flags);
-+
-+      bounce_free(buf->pool, buf->safe, buf->size);
-+
-+      kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+      if (!dev || !g_dmabounce_device_info)
-+              return NULL;
-+      if (dma_mapping_error(dev, dma_addr)) {
-+              dev_err(dev, "Trying to %s invalid mapping\n", where);
-+              return NULL;
-+      }
-+      return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+         enum dma_data_direction dir, unsigned long attrs)
-+{
-+      BUG_ON(buf->size != size);
-+      BUG_ON(buf->direction != dir);
-+
-+      dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+              (u64)buf->safe_dma_addr);
-+
-+      if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+          !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+              bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+                                   size);
-+
-+      return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+           enum dma_data_direction dir, unsigned long attrs)
-+{
-+      BUG_ON(buf->size != size);
-+      BUG_ON(buf->direction != dir);
-+
-+      if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+          !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+              dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+                      (u64)buf->unsafe_dma_addr);
-+
-+              bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+                                   size);
-+      }
-+      return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range.  if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+                 size_t size, enum dma_data_direction dir,
-+                 unsigned long attrs)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+      dma_addr_t dma_addr;
-+
-+      dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
-+
-+      arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+      if (device_info && (dma_addr + size) > device_info->threshold) {
-+              struct safe_buffer *buf;
-+
-+              buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+              if (!buf) {
-+                      DO_STATS(device_info->fail_count++);
-+                      return DMA_MAPPING_ERROR;
-+              }
-+
-+              DO_STATS(device_info->map_count++);
-+
-+              dma_addr = map_single(dev, buf, size, dir, attrs);
-+      }
-+
-+      return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer.  (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+                   enum dma_data_direction dir, unsigned long attrs)
-+{
-+      struct safe_buffer *buf;
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->unmap_count++);
-+              dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+              free_safe_buffer(g_dmabounce_device_info, buf);
-+      }
-+
-+      arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+                        enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+
-+      arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+              map_single(dev, buf, size, dir, 0);
-+      }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+                     size_t size, enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+              dma_addr = unmap_single(dev, buf, size, dir, 0);
-+      }
-+
-+      arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+      if (g_dmabounce_device_info)
-+              return 0;
-+
-+      return arm_dma_ops.dma_supported(dev, dma_mask);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+      .alloc                  = arm_dma_alloc,
-+      .free                   = arm_dma_free,
-+      .mmap                   = arm_dma_mmap,
-+      .get_sgtable            = arm_dma_get_sgtable,
-+      .map_page               = dmabounce_map_page,
-+      .unmap_page             = dmabounce_unmap_page,
-+      .sync_single_for_cpu    = dmabounce_sync_for_cpu,
-+      .sync_single_for_device = dmabounce_sync_for_device,
-+      .map_sg                 = arm_dma_map_sg,
-+      .unmap_sg               = arm_dma_unmap_sg,
-+      .sync_sg_for_cpu        = arm_dma_sync_sg_for_cpu,
-+      .sync_sg_for_device     = arm_dma_sync_sg_for_device,
-+      .dma_supported          = dmabounce_dma_supported,
-+};
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev,
-+                                unsigned long buffer_size,
-+                                dma_addr_t threshold)
-+{
-+      struct dmabounce_device_info *device_info;
-+      int ret;
-+
-+      /* Only support a single client */
-+      if (g_dmabounce_device_info)
-+              return -EBUSY;
-+
-+      ret = bcm2838_dma40_memcpy_init(dev);
-+      if (ret)
-+          return ret;
-+
-+      device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+      if (!device_info) {
-+              dev_err(dev,
-+                      "Could not allocated dmabounce_device_info\n");
-+              return -ENOMEM;
-+      }
-+
-+      ret = bounce_create(&device_info->pool, dev, buffer_size);
-+      if (ret) {
-+              dev_err(dev,
-+                      "dmabounce: could not allocate %ld byte DMA pool\n",
-+                      buffer_size);
-+              goto err_bounce;
-+      }
-+
-+      device_info->dev = dev;
-+      device_info->threshold = threshold;
-+      INIT_LIST_HEAD(&device_info->safe_buffers);
-+      rwlock_init(&device_info->lock);
-+
-+      DO_STATS(device_info->map_count = 0);
-+      DO_STATS(device_info->unmap_count = 0);
-+      DO_STATS(device_info->sync_dev_count = 0);
-+      DO_STATS(device_info->sync_cpu_count = 0);
-+      DO_STATS(device_info->fail_count = 0);
-+      DO_STATS(device_info->attr_res =
-+               device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+      g_dmabounce_device_info = device_info;
-+      set_dma_ops(dev, &dmabounce_ops);
-+
-+      dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+               buffer_size / 1024, &threshold);
-+
-+      return 0;
-+
-+ err_bounce:
-+      kfree(device_info);
-+      return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+      g_dmabounce_device_info = NULL;
-+      set_dma_ops(dev, NULL);
-+
-+      if (!device_info) {
-+              dev_warn(dev,
-+                       "Never registered with dmabounce but attempting"
-+                       "to unregister!\n");
-+              return;
-+      }
-+
-+      if (!list_empty(&device_info->safe_buffers)) {
-+              dev_err(dev,
-+                      "Removing from dmabounce with pending buffers!\n");
-+              BUG();
-+      }
-+
-+      bounce_destroy(&device_info->pool);
-+
-+      DO_STATS(if (device_info->attr_res == 0)
-+                       device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+      kfree(device_info);
-+
-+      dev_info(dev, "dmabounce: device unregistered\n");
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+
-+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ *  Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ */
-+
-+#ifndef _PCIE_BRCMSTB_BOUNCE_H
-+#define _PCIE_BRCMSTB_BOUNCE_H
-+
-+#ifdef CONFIG_ARM
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
-+                                dma_addr_t threshold);
-+
-+int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+
-+#else
-+
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev,
-+                                              unsigned long buffer_size,
-+                                              dma_addr_t threshold)
-+{
-+      return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+      return 0;
-+}
-+
-+#endif
-+
-+#endif /* _PCIE_BRCMSTB_BOUNCE_H */
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -29,6 +29,7 @@
- #include <linux/string.h>
- #include <linux/types.h>
- #include "../pci.h"
-+#include "pcie-brcmstb-bounce.h"
- /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
- #define BRCM_PCIE_CAP_REGS                            0x00ac
-@@ -53,6 +54,7 @@
- #define PCIE_MISC_MSI_BAR_CONFIG_LO                   0x4044
- #define PCIE_MISC_MSI_BAR_CONFIG_HI                   0x4048
- #define PCIE_MISC_MSI_DATA_CONFIG                     0x404c
-+#define PCIE_MISC_EOI_CTRL                            0x4060
- #define PCIE_MISC_PCIE_CTRL                           0x4064
- #define PCIE_MISC_PCIE_STATUS                         0x4068
- #define PCIE_MISC_REVISION                            0x406c
-@@ -260,12 +262,14 @@ struct brcm_pcie {
-       unsigned int            rev;
-       const int               *reg_offsets;
-       const int               *reg_field_info;
-+      u32                     max_burst_size;
-       enum pcie_type          type;
- };
- struct pcie_cfg_data {
-       const int               *reg_field_info;
-       const int               *offsets;
-+      const u32               max_burst_size;
-       const enum pcie_type    type;
- };
-@@ -288,24 +292,27 @@ static const int pcie_offset_bcm7425[] =
- static const struct pcie_cfg_data bcm7425_cfg = {
-       .reg_field_info = pcie_reg_field_info,
-       .offsets        = pcie_offset_bcm7425,
-+      .max_burst_size = BURST_SIZE_256,
-       .type           = BCM7425,
- };
- static const int pcie_offsets[] = {
-       [RGR1_SW_INIT_1] = 0x9210,
-       [EXT_CFG_INDEX]  = 0x9000,
--      [EXT_CFG_DATA]   = 0x9004,
-+      [EXT_CFG_DATA]   = 0x8000,
- };
- static const struct pcie_cfg_data bcm7435_cfg = {
-       .reg_field_info = pcie_reg_field_info,
-       .offsets        = pcie_offsets,
-+      .max_burst_size = BURST_SIZE_256,
-       .type           = BCM7435,
- };
- static const struct pcie_cfg_data generic_cfg = {
-       .reg_field_info = pcie_reg_field_info,
-       .offsets        = pcie_offsets,
-+      .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
-       .type           = GENERIC,
- };
-@@ -318,6 +325,7 @@ static const int pcie_offset_bcm7278[] =
- static const struct pcie_cfg_data bcm7278_cfg = {
-       .reg_field_info = pcie_reg_field_info_bcm7278,
-       .offsets        = pcie_offset_bcm7278,
-+      .max_burst_size = BURST_SIZE_512,
-       .type           = BCM7278,
- };
-@@ -360,7 +368,6 @@ static struct pci_ops brcm_pcie_ops = {
-        (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
- static const struct dma_map_ops *arch_dma_ops;
--static const struct dma_map_ops *brcm_dma_ops_ptr;
- static struct of_pci_range *dma_ranges;
- static int num_dma_ranges;
-@@ -369,6 +376,16 @@ static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-+static unsigned int bounce_buffer = 32*1024*1024;
-+module_param(bounce_buffer, uint, 0644);
-+MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
-+
-+static unsigned int bounce_threshold = 0xc0000000;
-+module_param(bounce_threshold, uint, 0644);
-+MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
-+
-+static struct brcm_pcie *g_pcie;
-+
- static dma_addr_t brcm_to_pci(dma_addr_t addr)
- {
-       struct of_pci_range *p;
-@@ -457,12 +474,10 @@ static int brcm_map_sg(struct device *de
-       struct scatterlist *sg;
-       for_each_sg(sgl, sg, nents, i) {
--#ifdef CONFIG_NEED_SG_DMA_LENGTH
--              sg->dma_length = sg->length;
--#endif
-+              sg_dma_len(sg) = sg->length;
-               sg->dma_address =
--                      brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
--                                                 sg->length, dir, attrs);
-+                      brcm_map_page(dev, sg_page(sg), sg->offset,
-+                                    sg->length, dir, attrs);
-               if (dma_mapping_error(dev, sg->dma_address))
-                       goto bad_mapping;
-       }
-@@ -470,8 +485,8 @@ static int brcm_map_sg(struct device *de
- bad_mapping:
-       for_each_sg(sgl, sg, i, j)
--              brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
--                                           sg_dma_len(sg), dir, attrs);
-+              brcm_unmap_page(dev, sg_dma_address(sg),
-+                              sg_dma_len(sg), dir, attrs);
-       return 0;
- }
-@@ -484,8 +499,8 @@ static void brcm_unmap_sg(struct device
-       struct scatterlist *sg;
-       for_each_sg(sgl, sg, nents, i)
--              brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
--                                           sg_dma_len(sg), dir, attrs);
-+              brcm_unmap_page(dev, sg_dma_address(sg),
-+                              sg_dma_len(sg), dir, attrs);
- }
- static void brcm_sync_single_for_cpu(struct device *dev,
-@@ -531,8 +546,8 @@ void brcm_sync_sg_for_cpu(struct device
-       int i;
-       for_each_sg(sgl, sg, nents, i)
--              brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
--                                                    sg->length, dir);
-+              brcm_sync_single_for_cpu(dev, sg_dma_address(sg),
-+                                       sg->length, dir);
- }
- void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-@@ -542,14 +557,9 @@ void brcm_sync_sg_for_device(struct devi
-       int i;
-       for_each_sg(sgl, sg, nents, i)
--              brcm_dma_ops_ptr->sync_single_for_device(dev,
--                                                       sg_dma_address(sg),
--                                                       sg->length, dir);
--}
--
--static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
--{
--      return arch_dma_ops->mapping_error(dev, dma_addr);
-+              brcm_sync_single_for_device(dev,
-+                                          sg_dma_address(sg),
-+                                          sg->length, dir);
- }
- static int brcm_dma_supported(struct device *dev, u64 mask)
-@@ -572,7 +582,7 @@ static int brcm_dma_supported(struct dev
- }
- #ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
--u64 brcm_get_required_mask)(struct device *dev)
-+u64 brcm_get_required_mask(struct device *dev)
- {
-       return arch_dma_ops->get_required_mask(dev);
- }
-@@ -593,7 +603,6 @@ static const struct dma_map_ops brcm_dma
-       .sync_single_for_device = brcm_sync_single_for_device,
-       .sync_sg_for_cpu        = brcm_sync_sg_for_cpu,
-       .sync_sg_for_device     = brcm_sync_sg_for_device,
--      .mapping_error          = brcm_mapping_error,
-       .dma_supported          = brcm_dma_supported,
- #ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-       .get_required_mask      = brcm_get_required_mask,
-@@ -633,17 +642,47 @@ static void brcm_set_dma_ops(struct devi
-       set_dma_ops(dev, &brcm_dma_ops);
- }
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+                                     unsigned int val);
- static int brcmstb_platform_notifier(struct notifier_block *nb,
-                                    unsigned long event, void *__dev)
- {
-+      extern unsigned long max_pfn;
-       struct device *dev = __dev;
-+      const char *rc_name = "0000:00:00.0";
--      brcm_dma_ops_ptr = &brcm_dma_ops;
--      if (event != BUS_NOTIFY_ADD_DEVICE)
--              return NOTIFY_DONE;
-+      switch (event) {
-+      case BUS_NOTIFY_ADD_DEVICE:
-+              if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
-+                  strcmp(dev->kobj.name, rc_name)) {
-+                      int ret;
-+
-+                      ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
-+                                                          (dma_addr_t)bounce_threshold);
-+                      if (ret) {
-+                              dev_err(dev,
-+                                      "brcm_pcie_bounce_register_dev() failed: %d\n",
-+                              ret);
-+                              return ret;
-+                      }
-+              }
-+              brcm_set_dma_ops(dev);
-+              return NOTIFY_OK;
--      brcm_set_dma_ops(dev);
--      return NOTIFY_OK;
-+      case BUS_NOTIFY_DEL_DEVICE:
-+              if (!strcmp(dev->kobj.name, rc_name) && g_pcie) {
-+                      /* Force a bus reset */
-+                      brcm_pcie_perst_set(g_pcie, 1);
-+                      msleep(100);
-+                      brcm_pcie_perst_set(g_pcie, 0);
-+              } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+                      brcm_pcie_bounce_unregister_dev(dev);
-+              }
-+              return NOTIFY_OK;
-+
-+      default:
-+              return NOTIFY_DONE;
-+      }
- }
- static struct notifier_block brcmstb_platform_nb = {
-@@ -914,6 +953,7 @@ static void brcm_pcie_msi_isr(struct irq
-               }
-       }
-       chained_irq_exit(chip, desc);
-+      bcm_writel(1, msi->base + PCIE_MISC_EOI_CTRL);
- }
- static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-@@ -930,7 +970,8 @@ static void brcm_compose_msi_msg(struct
- static int brcm_msi_set_affinity(struct irq_data *irq_data,
-                                const struct cpumask *mask, bool force)
- {
--      return -EINVAL;
-+      struct brcm_msi *msi = irq_data_get_irq_chip_data(irq_data);
-+      return __irq_set_affinity(msi->irq, mask, force);
- }
- static struct irq_chip brcm_msi_bottom_irq_chip = {
-@@ -1168,9 +1209,9 @@ static void __iomem *brcm_pcie_map_conf(
-               return PCI_SLOT(devfn) ? NULL : base + where;
-       /* For devices, write to the config space index register */
--      idx = cfg_index(bus->number, devfn, where);
-+      idx = cfg_index(bus->number, devfn, 0);
-       bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
--      return base + DATA_ADDR(pcie) + (where & 0x3);
-+      return base + DATA_ADDR(pcie) + where;
- }
- static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-@@ -1238,20 +1279,6 @@ static int brcm_pcie_parse_map_dma_range
-                       num_dma_ranges++;
-       }
--      for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
--              u64 size = brcmstb_memory_memc_size(i);
--
--              if (size == (u64)-1) {
--                      dev_err(pcie->dev, "cannot get memc%d size", i);
--                      return -EINVAL;
--              } else if (size) {
--                      scb_size[i] = roundup_pow_of_two_64(size);
--                      num_memc++;
--              } else {
--                      break;
--              }
--      }
--
-       return 0;
- }
-@@ -1275,26 +1302,25 @@ static int brcm_pcie_add_controller(stru
-       if (ret)
-               goto done;
--      /* Determine num_memc and their sizes */
--      for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
--              u64 size = brcmstb_memory_memc_size(i);
--
--              if (size == (u64)-1) {
--                      dev_err(dev, "cannot get memc%d size\n", i);
--                      ret = -EINVAL;
--                      goto done;
--              } else if (size) {
--                      scb_size[i] = roundup_pow_of_two_64(size);
--                      num_memc++;
--              } else {
--                      break;
-+      if (!num_dma_ranges) {
-+              /* Determine num_memc and their sizes by other means */
-+              for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+                      u64 size = brcmstb_memory_memc_size(i);
-+
-+                      if (size == (u64)-1) {
-+                              dev_err(dev, "cannot get memc%d size\n", i);
-+                              ret = -EINVAL;
-+                              goto done;
-+                      } else if (size) {
-+                              scb_size[i] = roundup_pow_of_two_64(size);
-+                      } else {
-+                              break;
-+                      }
-               }
--      }
--      if (!ret && num_memc == 0) {
--              ret = -EINVAL;
--              goto done;
-+              num_memc = i;
-       }
-+      g_pcie = pcie;
-       num_pcie++;
- done:
-       mutex_unlock(&brcm_pcie_lock);
-@@ -1307,6 +1333,7 @@ static void brcm_pcie_remove_controller(
-       if (--num_pcie > 0)
-               goto out;
-+      g_pcie = NULL;
-       if (brcm_unregister_notifier())
-               dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
-       kfree(dma_ranges);
-@@ -1367,7 +1394,7 @@ static int brcm_pcie_setup(struct brcm_p
-       void __iomem *base = pcie->base;
-       unsigned int scb_size_val;
-       u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
--      u32 tmp, burst;
-+      u32 tmp;
-       int i, j, ret, limit;
-       u16 nlw, cls, lnksta;
-       bool ssc_good = false;
-@@ -1400,20 +1427,15 @@ static int brcm_pcie_setup(struct brcm_p
-       /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
-       tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
-       tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
--      burst = (pcie->type == GENERIC || pcie->type == BCM7278)
--              ? BURST_SIZE_512 : BURST_SIZE_256;
--      tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+      tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE,
-+                         pcie->max_burst_size);
-       bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-       /*
-        * Set up inbound memory view for the EP (called RC_BAR2,
-        * not to be confused with the BARs that are advertised by
-        * the EP).
--       */
--      for (i = 0; i < num_memc; i++)
--              total_mem_size += scb_size[i];
--
--      /*
-+       *
-        * The PCIe host controller by design must set the inbound
-        * viewport to be a contiguous arrangement of all of the
-        * system's memory.  In addition, its size mut be a power of
-@@ -1429,55 +1451,49 @@ static int brcm_pcie_setup(struct brcm_p
-        * the controller will know to send outbound memory downstream
-        * and everything else upstream.
-        */
--      rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
--      if (dma_ranges) {
-+      if (num_dma_ranges) {
-               /*
--               * The best-case scenario is to place the inbound
--               * region in the first 4GB of pcie-space, as some
--               * legacy devices can only address 32bits.
--               * We would also like to put the MSI under 4GB
--               * as well, since some devices require a 32bit
--               * MSI target address.
-+               * Use the base address and size(s) provided in the dma-ranges
-+               * property.
-                */
--              if (total_mem_size <= 0xc0000000ULL &&
--                  rc_bar2_size <= 0x100000000ULL) {
--                      rc_bar2_offset = 0;
--                      /* If the viewport is less then 4GB we can fit
--                       * the MSI target address under 4GB. Otherwise
--                       * put it right below 64GB.
--                       */
--                      msi_target_addr =
--                              (rc_bar2_size == 0x100000000ULL)
--                              ? BRCM_MSI_TARGET_ADDR_GT_4GB
--                              : BRCM_MSI_TARGET_ADDR_LT_4GB;
--              } else {
--                      /*
--                       * The system memory is 4GB or larger so we
--                       * cannot start the inbound region at location
--                       * 0 (since we have to allow some space for
--                       * outbound memory @ 3GB).  So instead we
--                       * start it at the 1x multiple of its size
--                       */
--                      rc_bar2_offset = rc_bar2_size;
--
--                      /* Since we are starting the viewport at 4GB or
--                       * higher, put the MSI target address below 4GB
--                       */
--                      msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
--              }
--      } else {
-+              for (i = 0; i < num_dma_ranges; i++)
-+                      scb_size[i] = roundup_pow_of_two_64(dma_ranges[i].size);
-+
-+              num_memc = num_dma_ranges;
-+              rc_bar2_offset = dma_ranges[0].pci_addr;
-+      } else if (num_memc) {
-               /*
-                * Set simple configuration based on memory sizes
--               * only.  We always start the viewport at address 0,
--               * and set the MSI target address accordingly.
-+               * only.  We always start the viewport at address 0.
-                */
-               rc_bar2_offset = 0;
-+      } else {
-+              return -EINVAL;
-+      }
-+
-+      for (i = 0; i < num_memc; i++)
-+              total_mem_size += scb_size[i];
-+
-+      rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
--              msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
--                      ? BRCM_MSI_TARGET_ADDR_GT_4GB
--                      : BRCM_MSI_TARGET_ADDR_LT_4GB;
-+      /* Verify the alignment is correct */
-+      if (rc_bar2_offset & (rc_bar2_size - 1)) {
-+              dev_err(dev, "inbound window is misaligned\n");
-+              return -EINVAL;
-       }
-+
-+      /*
-+       * Position the MSI target low if possible.
-+       *
-+       * TO DO: Consider outbound window when choosing MSI target and
-+       * verifying configuration.
-+       */
-+      msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+      if (rc_bar2_offset <= msi_target_addr &&
-+          rc_bar2_offset + rc_bar2_size > msi_target_addr)
-+              msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
-+
-       pcie->msi_target_addr = msi_target_addr;
-       tmp = lower_32_bits(rc_bar2_offset);
-@@ -1713,6 +1729,7 @@ static int brcm_pcie_probe(struct platfo
-       data = of_id->data;
-       pcie->reg_offsets = data->offsets;
-       pcie->reg_field_info = data->reg_field_info;
-+      pcie->max_burst_size = data->max_burst_size;
-       pcie->type = data->type;
-       pcie->dn = dn;
-       pcie->dev = &pdev->dev;
-@@ -1732,7 +1749,7 @@ static int brcm_pcie_probe(struct platfo
-       pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-       if (IS_ERR(pcie->clk)) {
--              dev_err(&pdev->dev, "could not get clock\n");
-+              dev_warn(&pdev->dev, "could not get clock\n");
-               pcie->clk = NULL;
-       }
-       pcie->base = base;
-@@ -1755,7 +1772,8 @@ static int brcm_pcie_probe(struct platfo
-       ret = clk_prepare_enable(pcie->clk);
-       if (ret) {
--              dev_err(&pdev->dev, "could not enable clock\n");
-+              if (ret != -EPROBE_DEFER)
-+                      dev_err(&pdev->dev, "could not enable clock\n");
-               return ret;
-       }
-@@ -1818,7 +1836,6 @@ static struct platform_driver brcm_pcie_
-       .remove = brcm_pcie_remove,
-       .driver = {
-               .name = "brcm-pcie",
--              .owner = THIS_MODULE,
-               .of_match_table = brcm_pcie_match,
-               .pm = &brcm_pcie_pm_ops,
-       },
---- a/drivers/soc/bcm/brcmstb/Makefile
-+++ b/drivers/soc/bcm/brcmstb/Makefile
-@@ -1,3 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0-only
--obj-y                         += common.o biuctrl.o
-+obj-y                         += common.o biuctrl.o memory.o
- obj-$(CONFIG_BRCMSTB_PM)      += pm/
---- /dev/null
-+++ b/drivers/soc/bcm/brcmstb/memory.c
-@@ -0,0 +1,158 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright © 2015-2017 Broadcom */
-+
-+#include <linux/device.h>
-+#include <linux/io.h>
-+#include <linux/libfdt.h>
-+#include <linux/of_address.h>
-+#include <linux/of_fdt.h>
-+#include <linux/sizes.h>
-+#include <soc/brcmstb/memory_api.h>
-+
-+/* Macro to help extract property data */
-+#define DT_PROP_DATA_TO_U32(b, offs) (fdt32_to_cpu(*(u32 *)(b + offs)))
-+
-+/* Constants used when retrieving memc info */
-+#define NUM_BUS_RANGES 10
-+#define BUS_RANGE_ULIMIT_SHIFT 4
-+#define BUS_RANGE_LLIMIT_SHIFT 4
-+#define BUS_RANGE_PA_SHIFT 12
-+
-+enum {
-+      BUSNUM_MCP0 = 0x4,
-+      BUSNUM_MCP1 = 0x5,
-+      BUSNUM_MCP2 = 0x6,
-+};
-+
-+/*
-+ * If the DT nodes are handy, determine which MEMC holds the specified
-+ * physical address.
-+ */
-+#ifdef CONFIG_ARCH_BRCMSTB
-+int __brcmstb_memory_phys_addr_to_memc(phys_addr_t pa, void __iomem *base)
-+{
-+      int memc = -1;
-+      int i;
-+
-+      for (i = 0; i < NUM_BUS_RANGES; i++, base += 8) {
-+              const u64 ulimit_raw = readl(base);
-+              const u64 llimit_raw = readl(base + 4);
-+              const u64 ulimit =
-+                      ((ulimit_raw >> BUS_RANGE_ULIMIT_SHIFT)
-+                       << BUS_RANGE_PA_SHIFT) | 0xfff;
-+              const u64 llimit = (llimit_raw >> BUS_RANGE_LLIMIT_SHIFT)
-+                                 << BUS_RANGE_PA_SHIFT;
-+              const u32 busnum = (u32)(ulimit_raw & 0xf);
-+
-+              if (pa >= llimit && pa <= ulimit) {
-+                      if (busnum >= BUSNUM_MCP0 && busnum <= BUSNUM_MCP2) {
-+                              memc = busnum - BUSNUM_MCP0;
-+                              break;
-+                      }
-+              }
-+      }
-+
-+      return memc;
-+}
-+
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+      int memc = -1;
-+      struct device_node *np;
-+      void __iomem *cpubiuctrl;
-+
-+      np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
-+      if (!np)
-+              return memc;
-+
-+      cpubiuctrl = of_iomap(np, 0);
-+      if (!cpubiuctrl)
-+              goto cleanup;
-+
-+      memc = __brcmstb_memory_phys_addr_to_memc(pa, cpubiuctrl);
-+      iounmap(cpubiuctrl);
-+
-+cleanup:
-+      of_node_put(np);
-+
-+      return memc;
-+}
-+
-+#elif defined(CONFIG_MIPS)
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+      /* The logic here is fairly simple and hardcoded: if pa <= 0x5000_0000,
-+       * then this is MEMC0, else MEMC1.
-+       *
-+       * For systems with 2GB on MEMC0, MEMC1 starts at 9000_0000, with 1GB
-+       * on MEMC0, MEMC1 starts at 6000_0000.
-+       */
-+      if (pa >= 0x50000000ULL)
-+              return 1;
-+      else
-+              return 0;
-+}
-+#endif
-+
-+u64 brcmstb_memory_memc_size(int memc)
-+{
-+      const void *fdt = initial_boot_params;
-+      const int mem_offset = fdt_path_offset(fdt, "/memory");
-+      int addr_cells = 1, size_cells = 1;
-+      const struct fdt_property *prop;
-+      int proplen, cellslen;
-+      u64 memc_size = 0;
-+      int i;
-+
-+      /* Get root size and address cells if specified */
-+      prop = fdt_get_property(fdt, 0, "#size-cells", &proplen);
-+      if (prop)
-+              size_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+      prop = fdt_get_property(fdt, 0, "#address-cells", &proplen);
-+      if (prop)
-+              addr_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+      if (mem_offset < 0)
-+              return -1;
-+
-+      prop = fdt_get_property(fdt, mem_offset, "reg", &proplen);
-+      cellslen = (int)sizeof(u32) * (addr_cells + size_cells);
-+      if ((proplen % cellslen) != 0)
-+              return -1;
-+
-+      for (i = 0; i < proplen / cellslen; ++i) {
-+              u64 addr = 0;
-+              u64 size = 0;
-+              int memc_idx;
-+              int j;
-+
-+              for (j = 0; j < addr_cells; ++j) {
-+                      int offset = (cellslen * i) + (sizeof(u32) * j);
-+
-+                      addr |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+                              ((addr_cells - j - 1) * 32);
-+              }
-+              for (j = 0; j < size_cells; ++j) {
-+                      int offset = (cellslen * i) +
-+                              (sizeof(u32) * (j + addr_cells));
-+
-+                      size |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+                              ((size_cells - j - 1) * 32);
-+              }
-+
-+              if ((phys_addr_t)addr != addr) {
-+                      pr_err("phys_addr_t is smaller than provided address 0x%llx!\n",
-+                             addr);
-+                      return -1;
-+              }
-+
-+              memc_idx = brcmstb_memory_phys_addr_to_memc((phys_addr_t)addr);
-+              if (memc_idx == memc)
-+                      memc_size += size;
-+      }
-+
-+      return memc_size;
-+}
-+EXPORT_SYMBOL_GPL(brcmstb_memory_memc_size);
-+
similarity index 66%
rename from target/linux/bcm27xx/patches-5.4/950-0223-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch
rename to target/linux/bcm27xx/patches-5.4/950-0219-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch
index b5e5c039c3827e245cbf620df5b65be61bf6510e..4e3805d9a712e00b7d3742f926d6ac3855799b23 100644 (file)
@@ -28,17 +28,3 @@ Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835
        help
          This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
          This SoC is used in the Raspberry Pi and Roku 2 devices.
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -290,9 +290,9 @@ config PCI_HYPERV_INTERFACE
- config PCIE_BRCMSTB
-       tristate "Broadcom Brcmstb PCIe platform host driver"
--      depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+      depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835
-       depends on OF
--      depends on SOC_BRCMSTB
-+      depends on SOC_BRCMSTB || ARCH_BCM2835
-       default ARCH_BRCMSTB || BMIPS_GENERIC
-       help
-         Adds support for Broadcom Settop Box PCIe host controller.
diff --git a/target/linux/bcm27xx/patches-5.4/950-0274-arm64-mm-Limit-the-DMA-zone-for-arm64.patch b/target/linux/bcm27xx/patches-5.4/950-0274-arm64-mm-Limit-the-DMA-zone-for-arm64.patch
deleted file mode 100644 (file)
index e2c47c4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 235f775351e8f7e47cff1baa1284e0df95e3234e Mon Sep 17 00:00:00 2001
-From: Andrei Gherzan <andrei@balena.io>
-Date: Tue, 16 Jul 2019 13:28:22 +0100
-Subject: [PATCH] arm64/mm: Limit the DMA zone for arm64
-
-On RaspberryPi, only the first 1Gb can be used for DMA[1].
-
-[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2019-July/665986.html
-
-Signed-off-by: Andrei Gherzan <andrei@balena.io>
----
- arch/arm64/mm/init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm64/mm/init.c
-+++ b/arch/arm64/mm/init.c
-@@ -177,7 +177,7 @@ static void __init reserve_elfcorehdr(vo
- static phys_addr_t __init max_zone_dma_phys(void)
- {
-       phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
--      return min(offset + (1ULL << 32), memblock_end_of_DRAM());
-+      return min(offset + (1ULL << 30), memblock_end_of_DRAM());
- }
- #ifdef CONFIG_NUMA
diff --git a/target/linux/bcm27xx/patches-5.4/950-0276-bcm2835-dma-Add-proper-40-bit-DMA-support.patch b/target/linux/bcm27xx/patches-5.4/950-0276-bcm2835-dma-Add-proper-40-bit-DMA-support.patch
deleted file mode 100644 (file)
index 60610d5..0000000
+++ /dev/null
@@ -1,945 +0,0 @@
-From 773a2db89ad2785d72b215673d87c0a51d769f61 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 4 Apr 2019 13:33:47 +0100
-Subject: [PATCH] bcm2835-dma: Add proper 40-bit DMA support
-
-The 40-bit additions are not fully tested, but it should be
-capable of supporting both 40-bit memcpy on BCM2711 and regular
-Lite channels on BCM2835.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/dma/bcm2835-dma.c                    | 421 ++++++++++++++-----
- drivers/pci/controller/pcie-brcmstb-bounce.c |  30 +-
- drivers/pci/controller/pcie-brcmstb-bounce.h |  21 +-
- drivers/pci/controller/pcie-brcmstb.c        |  23 +-
- 4 files changed, 369 insertions(+), 126 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -38,6 +38,11 @@
- #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
- #define BCM2835_DMA_CHAN_NAME_SIZE 8
- #define BCM2835_DMA_BULK_MASK  BIT(0)
-+#define BCM2838_DMA_MEMCPY_CHAN 14
-+
-+struct bcm2835_dma_cfg_data {
-+      u32     chan_40bit_mask;
-+};
- /**
-  * struct bcm2835_dmadev - BCM2835 DMA controller
-@@ -52,6 +57,7 @@ struct bcm2835_dmadev {
-       void __iomem *base;
-       struct device_dma_parameters dma_parms;
-       dma_addr_t zero_page;
-+      const struct bcm2835_dma_cfg_data *cfg_data;
- };
- struct bcm2835_dma_cb {
-@@ -95,6 +101,7 @@ struct bcm2835_chan {
-       unsigned int irq_flags;
-       bool is_lite_channel;
-+      bool is_40bit_channel;
- };
- struct bcm2835_desc {
-@@ -184,7 +191,8 @@ struct bcm2835_desc {
- #define BCM2835_DMA_DATA_TYPE_S128    16
- /* Valid only for channels 0 - 14, 15 has its own base address */
--#define BCM2835_DMA_CHAN(n)   ((n) << 8) /* Base address */
-+#define BCM2835_DMA_CHAN_SIZE 0x100
-+#define BCM2835_DMA_CHAN(n)   ((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
- #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
- /* the max dma length for different channels */
-@@ -195,7 +203,7 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_CS      0x00
- #define BCM2838_DMA40_CB      0x04
- #define BCM2838_DMA40_DEBUG   0x0c
--#define BCM2858_DMA40_TI      0x10
-+#define BCM2838_DMA40_TI      0x10
- #define BCM2838_DMA40_SRC     0x14
- #define BCM2838_DMA40_SRCI    0x18
- #define BCM2838_DMA40_DEST    0x1c
-@@ -204,32 +212,97 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_NEXT_CB 0x28
- #define BCM2838_DMA40_DEBUG2  0x2c
--#define BCM2838_DMA40_CS_ACTIVE       BIT(0)
--#define BCM2838_DMA40_CS_END  BIT(1)
-+#define BCM2838_DMA40_ACTIVE          BIT(0)
-+#define BCM2838_DMA40_END             BIT(1)
-+#define BCM2838_DMA40_INT             BIT(2)
-+#define BCM2838_DMA40_DREQ            BIT(3)  /* DREQ state */
-+#define BCM2838_DMA40_RD_PAUSED               BIT(4)  /* Reading is paused */
-+#define BCM2838_DMA40_WR_PAUSED               BIT(5)  /* Writing is paused */
-+#define BCM2838_DMA40_DREQ_PAUSED     BIT(6)  /* Is paused by DREQ flow control */
-+#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7)  /* Waiting for last write */
-+#define BCM2838_DMA40_ERR             BIT(10)
-+#define BCM2838_DMA40_QOS(x)          (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_PANIC_QOS(x)    (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
-+#define BCM2838_DMA40_DISDEBUG                BIT(29)
-+#define BCM2838_DMA40_ABORT           BIT(30)
-+#define BCM2838_DMA40_HALT            BIT(31)
-+#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
-+                                      BCM2838_DMA40_PANIC_QOS(15) | \
-+                                      BCM2838_DMA40_WAIT_FOR_WRITES | \
-+                                      BCM2838_DMA40_DISDEBUG))
-+
-+/* Transfer information bits */
-+#define BCM2838_DMA40_INTEN           BIT(0)
-+#define BCM2838_DMA40_TDMODE          BIT(1) /* 2D-Mode */
-+#define BCM2838_DMA40_WAIT_RESP               BIT(2) /* wait for AXI write to be acked */
-+#define BCM2838_DMA40_WAIT_RD_RESP    BIT(3) /* wait for AXI read to complete */
-+#define BCM2838_DMA40_PER_MAP(x)      ((x & 31) << 9) /* REQ source */
-+#define BCM2838_DMA40_S_DREQ          BIT(14) /* enable SREQ for source */
-+#define BCM2838_DMA40_D_DREQ          BIT(15) /* enable DREQ for destination */
-+#define BCM2838_DMA40_S_WAIT(x)               ((x & 0xff) << 16) /* add DMA read-wait cycles */
-+#define BCM2838_DMA40_D_WAIT(x)               ((x & 0xff) << 24) /* add DMA write-wait cycles */
--#define BCM2838_DMA40_CS_QOS(x)       (((x) & 0x1f) << 16)
--#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
--#define BCM2838_DMA40_CS_WRITE_WAIT   BIT(28)
-+/* debug register bits */
-+#define BCM2838_DMA40_DEBUG_WRITE_ERR         BIT(0)
-+#define BCM2838_DMA40_DEBUG_FIFO_ERR          BIT(1)
-+#define BCM2838_DMA40_DEBUG_READ_ERR          BIT(2)
-+#define BCM2838_DMA40_DEBUG_READ_CB_ERR               BIT(3)
-+#define BCM2838_DMA40_DEBUG_IN_ON_ERR         BIT(8)
-+#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR      BIT(9)
-+#define BCM2838_DMA40_DEBUG_HALT_ON_ERR               BIT(10)
-+#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE  BIT(11)
-+#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT      14
-+#define BCM2838_DMA40_DEBUG_RSTATE_BITS               4
-+#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT      18
-+#define BCM2838_DMA40_DEBUG_WSTATE_BITS               4
-+#define BCM2838_DMA40_DEBUG_RESET             BIT(23)
-+#define BCM2838_DMA40_DEBUG_ID_SHIFT          24
-+#define BCM2838_DMA40_DEBUG_ID_BITS           4
-+#define BCM2838_DMA40_DEBUG_VERSION_SHIFT     28
-+#define BCM2838_DMA40_DEBUG_VERSION_BITS      4
-+
-+/* Valid only for channels 0 - 3 (11 - 14) */
-+#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
-+#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
--#define BCM2838_DMA40_BURST_LEN(x)    ((((x) - 1) & 0xf) << 8)
--#define BCM2838_DMA40_INC             BIT(12)
--#define BCM2838_DMA40_SIZE_128        (2 << 13)
-+/* the max dma length for different channels */
-+#define MAX_DMA40_LEN SZ_1G
--#define BCM2838_DMA40_MEMCPY_QOS \
--      (BCM2838_DMA40_CS_QOS(0x0) | \
--       BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
--       BCM2838_DMA40_CS_WRITE_WAIT)
-+#define BCM2838_DMA40_BURST_LEN(x)    ((min(x,16) - 1) << 8)
-+#define BCM2838_DMA40_INC             BIT(12)
-+#define BCM2838_DMA40_SIZE_32         (0 << 13)
-+#define BCM2838_DMA40_SIZE_64         (1 << 13)
-+#define BCM2838_DMA40_SIZE_128                (2 << 13)
-+#define BCM2838_DMA40_SIZE_256                (3 << 13)
-+#define BCM2838_DMA40_IGNORE          BIT(15)
-+#define BCM2838_DMA40_STRIDE(x)               ((x) << 16) /* For 2D mode */
-+
-+#define BCM2838_DMA40_MEMCPY_FLAGS \
-+      (BCM2838_DMA40_QOS(0) | \
-+       BCM2838_DMA40_PANIC_QOS(0) | \
-+       BCM2838_DMA40_WAIT_FOR_WRITES | \
-+       BCM2838_DMA40_DISDEBUG)
- #define BCM2838_DMA40_MEMCPY_XFER_INFO \
-       (BCM2838_DMA40_SIZE_128 | \
-        BCM2838_DMA40_INC | \
-        BCM2838_DMA40_BURST_LEN(16))
-+struct bcm2835_dmadev *memcpy_parent;
- static void __iomem *memcpy_chan;
- static struct bcm2838_dma40_scb *memcpy_scb;
- static dma_addr_t memcpy_scb_dma;
- DEFINE_SPINLOCK(memcpy_lock);
-+static const struct bcm2835_dma_cfg_data bcm2835_dma_cfg = {
-+      .chan_40bit_mask = 0,
-+};
-+
-+static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
-+      .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
-+};
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
-       /* lite and normal channels have different max frame length */
-@@ -259,6 +332,32 @@ static inline struct bcm2835_desc *to_bc
-       return container_of(t, struct bcm2835_desc, vd.tx);
- }
-+static inline uint32_t to_bcm2838_ti(uint32_t info)
-+{
-+      return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
-+              ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
-+              ((info & BCM2835_DMA_S_DREQ) ?
-+               (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
-+              ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
-+              BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
-+}
-+
-+static inline uint32_t to_bcm2838_srci(uint32_t info)
-+{
-+      return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_dsti(uint32_t info)
-+{
-+      return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
-+{
-+      BUG_ON(addr & 0x1f);
-+      return (addr >> 5);
-+}
-+
- static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
- {
-       size_t i;
-@@ -277,45 +376,53 @@ static void bcm2835_dma_desc_free(struct
- }
- static void bcm2835_dma_create_cb_set_length(
--      struct bcm2835_chan *chan,
-+      struct bcm2835_chan *c,
-       struct bcm2835_dma_cb *control_block,
-       size_t len,
-       size_t period_len,
-       size_t *total_len,
-       u32 finalextrainfo)
- {
--      size_t max_len = bcm2835_dma_max_frame_length(chan);
-+      size_t max_len = bcm2835_dma_max_frame_length(c);
-+      uint32_t cb_len;
-       /* set the length taking lite-channel limitations into account */
--      control_block->length = min_t(u32, len, max_len);
-+      cb_len = min_t(u32, len, max_len);
--      /* finished if we have no period_length */
--      if (!period_len)
--              return;
-+      if (period_len) {
-+              /*
-+               * period_len means: that we need to generate
-+               * transfers that are terminating at every
-+               * multiple of period_len - this is typically
-+               * used to set the interrupt flag in info
-+               * which is required during cyclic transfers
-+               */
--      /*
--       * period_len means: that we need to generate
--       * transfers that are terminating at every
--       * multiple of period_len - this is typically
--       * used to set the interrupt flag in info
--       * which is required during cyclic transfers
--       */
-+              /* have we filled in period_length yet? */
-+              if (*total_len + cb_len < period_len) {
-+                      /* update number of bytes in this period so far */
-+                      *total_len += cb_len;
-+              } else {
-+                      /* calculate the length that remains to reach period_len */
-+                      cb_len = period_len - *total_len;
--      /* have we filled in period_length yet? */
--      if (*total_len + control_block->length < period_len) {
--              /* update number of bytes in this period so far */
--              *total_len += control_block->length;
--              return;
-+                      /* reset total_length for next period */
-+                      *total_len = 0;
-+              }
-       }
--      /* calculate the length that remains to reach period_length */
--      control_block->length = period_len - *total_len;
--
--      /* reset total_length for next period */
--      *total_len = 0;
--
--      /* add extrainfo bits in info */
--      control_block->info |= finalextrainfo;
-+      if (c->is_40bit_channel) {
-+              struct bcm2838_dma40_scb *scb =
-+                      (struct bcm2838_dma40_scb *)control_block;
-+
-+              scb->len = cb_len;
-+              /* add extrainfo bits to ti */
-+              scb->ti |= to_bcm2838_ti(finalextrainfo);
-+      } else {
-+              control_block->length = cb_len;
-+              /* add extrainfo bits to info */
-+              control_block->info |= finalextrainfo;
-+      }
- }
- static inline size_t bcm2835_dma_count_frames_for_sg(
-@@ -338,7 +445,7 @@ static inline size_t bcm2835_dma_count_f
- /**
-  * bcm2835_dma_create_cb_chain - create a control block and fills data in
-  *
-- * @chan:           the @dma_chan for which we run this
-+ * @c:              the @bcm2835_chan for which we run this
-  * @direction:      the direction in which we transfer
-  * @cyclic:         it is a cyclic transfer
-  * @info:           the default info bits to apply per controlblock
-@@ -356,12 +463,11 @@ static inline size_t bcm2835_dma_count_f
-  * @gfp:            the GFP flag to use for allocation
-  */
- static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
--      struct dma_chan *chan, enum dma_transfer_direction direction,
-+      struct bcm2835_chan *c, enum dma_transfer_direction direction,
-       bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
-       dma_addr_t src, dma_addr_t dst, size_t buf_len,
-       size_t period_len, gfp_t gfp)
- {
--      struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-       size_t len = buf_len, total_len;
-       size_t frame;
-       struct bcm2835_desc *d;
-@@ -393,11 +499,23 @@ static struct bcm2835_desc *bcm2835_dma_
-               /* fill in the control block */
-               control_block = cb_entry->cb;
--              control_block->info = info;
--              control_block->src = src;
--              control_block->dst = dst;
--              control_block->stride = 0;
--              control_block->next = 0;
-+              if (c->is_40bit_channel) {
-+                      struct bcm2838_dma40_scb *scb =
-+                              (struct bcm2838_dma40_scb *)control_block;
-+                      scb->ti = to_bcm2838_ti(info);
-+                      scb->src = lower_32_bits(src);
-+                      scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
-+                      scb->dst = lower_32_bits(dst);
-+                      scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
-+                      scb->next_cb = 0;
-+              } else {
-+                      control_block->info = info;
-+                      control_block->src = src;
-+                      control_block->dst = dst;
-+                      control_block->stride = 0;
-+                      control_block->next = 0;
-+              }
-+
-               /* set up length in control_block if requested */
-               if (buf_len) {
-                       /* calculate length honoring period_length */
-@@ -411,7 +529,10 @@ static struct bcm2835_desc *bcm2835_dma_
-               }
-               /* link this the last controlblock */
--              if (frame)
-+              if (frame && c->is_40bit_channel)
-+                      d->cb_list[frame - 1].cb->next =
-+                              to_bcm2838_cbaddr(cb_entry->paddr);
-+              if (frame && !c->is_40bit_channel)
-                       d->cb_list[frame - 1].cb->next = cb_entry->paddr;
-               /* update src and dst and length */
-@@ -425,7 +546,14 @@ static struct bcm2835_desc *bcm2835_dma_
-       }
-       /* the last frame requires extra flags */
--      d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+      if (c->is_40bit_channel) {
-+              struct bcm2838_dma40_scb *scb =
-+                      (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
-+
-+              scb->ti |= to_bcm2838_ti(finalextrainfo);
-+      } else {
-+              d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+      }
-       /* detect a size missmatch */
-       if (buf_len && (d->size != buf_len))
-@@ -439,13 +567,12 @@ error_cb:
- }
- static void bcm2835_dma_fill_cb_chain_with_sg(
--      struct dma_chan *chan,
-+      struct bcm2835_chan *c,
-       enum dma_transfer_direction direction,
-       struct bcm2835_cb_entry *cb,
-       struct scatterlist *sgl,
-       unsigned int sg_len)
- {
--      struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-       size_t len, max_len;
-       unsigned int i;
-       dma_addr_t addr;
-@@ -453,14 +580,34 @@ static void bcm2835_dma_fill_cb_chain_wi
-       max_len = bcm2835_dma_max_frame_length(c);
-       for_each_sg(sgl, sgent, sg_len, i) {
--              for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
--                   len > 0;
--                   addr += cb->cb->length, len -= cb->cb->length, cb++) {
--                      if (direction == DMA_DEV_TO_MEM)
--                              cb->cb->dst = addr;
--                      else
--                              cb->cb->src = addr;
--                      cb->cb->length = min(len, max_len);
-+              if (c->is_40bit_channel) {
-+                      struct bcm2838_dma40_scb *scb =
-+                              (struct bcm2838_dma40_scb *)cb->cb;
-+                      for (addr = sg_dma_address(sgent),
-+                                   len = sg_dma_len(sgent);
-+                           len > 0;
-+                           addr += scb->len, len -= scb->len, scb++) {
-+                              if (direction == DMA_DEV_TO_MEM) {
-+                                      scb->dst = lower_32_bits(addr);
-+                                      scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+                              } else {
-+                                      scb->src = lower_32_bits(addr);
-+                                      scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+                              }
-+                              scb->len = min(len, max_len);
-+                      }
-+              } else {
-+                      for (addr = sg_dma_address(sgent),
-+                                   len = sg_dma_len(sgent);
-+                           len > 0;
-+                           addr += cb->cb->length, len -= cb->cb->length,
-+                           cb++) {
-+                              if (direction == DMA_DEV_TO_MEM)
-+                                      cb->cb->dst = addr;
-+                              else
-+                                      cb->cb->src = addr;
-+                              cb->cb->length = min(len, max_len);
-+                      }
-               }
-       }
- }
-@@ -469,6 +616,10 @@ static void bcm2835_dma_abort(struct bcm
- {
-       void __iomem *chan_base = c->chan_base;
-       long int timeout = 10000;
-+      u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
-+
-+      if (c->is_40bit_channel)
-+              wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
-       /*
-        * A zero control block address means the channel is idle.
-@@ -481,8 +632,7 @@ static void bcm2835_dma_abort(struct bcm
-       writel(0, chan_base + BCM2835_DMA_CS);
-       /* Wait for any current AXI transfer to complete */
--      while ((readl(chan_base + BCM2835_DMA_CS) &
--              BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
-+      while ((readl(chan_base + BCM2835_DMA_CS) & wait_mask) && --timeout)
-               cpu_relax();
-       /* Peripheral might be stuck and fail to signal AXI write responses */
-@@ -507,9 +657,16 @@ static void bcm2835_dma_start_desc(struc
-       c->desc = d = to_bcm2835_dma_desc(&vd->tx);
--      writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
--      writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
--             c->chan_base + BCM2835_DMA_CS);
-+      if (c->is_40bit_channel) {
-+              writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
-+                     c->chan_base + BCM2838_DMA40_CB);
-+              writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
-+                     c->chan_base + BCM2838_DMA40_CS);
-+      } else {
-+              writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-+              writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-+                     c->chan_base + BCM2835_DMA_CS);
-+      }
- }
- static irqreturn_t bcm2835_dma_callback(int irq, void *data)
-@@ -537,7 +694,8 @@ static irqreturn_t bcm2835_dma_callback(
-        * will remain idle despite the ACTIVE flag being set.
-        */
-       writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
--             BCM2835_DMA_CS_FLAGS(c->dreq),
-+             (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
-+              BCM2835_DMA_CS_FLAGS(c->dreq)),
-              c->chan_base + BCM2835_DMA_CS);
-       d = c->desc;
-@@ -640,9 +798,17 @@ static enum dma_status bcm2835_dma_tx_st
-               struct bcm2835_desc *d = c->desc;
-               dma_addr_t pos;
--              if (d->dir == DMA_MEM_TO_DEV)
-+              if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
-+                      pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
-+                              ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
-+                                0xff) << 8);
-+              else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
-                       pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
--              else if (d->dir == DMA_DEV_TO_MEM)
-+              else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
-+                      pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
-+                              ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
-+                                0xff) << 8);
-+              else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
-                       pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
-               else
-                       pos = 0;
-@@ -688,7 +854,7 @@ static struct dma_async_tx_descriptor *b
-       frames = bcm2835_dma_frames_for_length(len, max_len);
-       /* allocate the CB chain - this also fills in the pointers */
--      d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
-+      d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
-                                       info, extra, frames,
-                                       src, dst, len, 0, GFP_KERNEL);
-       if (!d)
-@@ -723,11 +889,21 @@ static struct dma_async_tx_descriptor *b
-               if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
-                       return NULL;
-               src = c->cfg.src_addr;
-+              /*
-+               * One would think it ought to be possible to get the physical
-+               * to dma address mapping information from the dma-ranges DT
-+               * property, but I've not found a way yet that doesn't involve
-+               * open-coding the whole thing.
-+               */
-+              if (c->is_40bit_channel)
-+                  src |= 0x400000000ull;
-               info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
-       } else {
-               if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
-                       return NULL;
-               dst = c->cfg.dst_addr;
-+              if (c->is_40bit_channel)
-+                  dst |= 0x400000000ull;
-               info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
-       }
-@@ -735,7 +911,7 @@ static struct dma_async_tx_descriptor *b
-       frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
-       /* allocate the CB chain */
--      d = bcm2835_dma_create_cb_chain(chan, direction, false,
-+      d = bcm2835_dma_create_cb_chain(c, direction, false,
-                                       info, extra,
-                                       frames, src, dst, 0, 0,
-                                       GFP_NOWAIT);
-@@ -743,7 +919,7 @@ static struct dma_async_tx_descriptor *b
-               return NULL;
-       /* fill in frames with scatterlist pointers */
--      bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
-+      bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
-                                         sgl, sg_len);
-       return vchan_tx_prep(&c->vc, &d->vd, flags);
-@@ -822,7 +998,7 @@ static struct dma_async_tx_descriptor *b
-        * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
-        * implementation calls prep_dma_cyclic with interrupts disabled.
-        */
--      d = bcm2835_dma_create_cb_chain(chan, direction, true,
-+      d = bcm2835_dma_create_cb_chain(c, direction, true,
-                                       info, extra,
-                                       frames, src, dst, buf_len,
-                                       period_len, GFP_NOWAIT);
-@@ -830,7 +1006,8 @@ static struct dma_async_tx_descriptor *b
-               return NULL;
-       /* wrap around into a loop */
--      d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
-+      d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
-+              to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-       return vchan_tx_prep(&c->vc, &d->vd, flags);
- }
-@@ -894,9 +1071,11 @@ static int bcm2835_dma_chan_init(struct
-       c->irq_number = irq;
-       c->irq_flags = irq_flags;
--      /* check in DEBUG register if this is a LITE channel */
--      if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
--              BCM2835_DMA_DEBUG_LITE)
-+      /* check for 40bit and lite channels */
-+      if (d->cfg_data->chan_40bit_mask & BIT(chan_id))
-+              c->is_40bit_channel = true;
-+      else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-+               BCM2835_DMA_DEBUG_LITE)
-               c->is_lite_channel = true;
-       return 0;
-@@ -916,18 +1095,16 @@ static void bcm2835_dma_free(struct bcm2
-                            DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
--int bcm2838_dma40_memcpy_init(struct device *dev)
-+int bcm2838_dma40_memcpy_init(void)
- {
--      if (memcpy_scb)
--              return 0;
-+      if (!memcpy_parent)
-+              return -EPROBE_DEFER;
--      memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
--                                      &memcpy_scb_dma, GFP_KERNEL);
-+      if (!memcpy_chan)
-+              return -EINVAL;
--      if (!memcpy_scb) {
--              pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+      if (!memcpy_scb)
-               return -ENOMEM;
--      }
-       return 0;
- }
-@@ -954,20 +1131,22 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
-       scb->next_cb = 0;
-       writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
--      writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+      writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
-              memcpy_chan + BCM2838_DMA40_CS);
-+
-       /* Poll for completion */
--      while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+      while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
-               cpu_relax();
--      writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+      writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
-       spin_unlock_irqrestore(&memcpy_lock, flags);
- }
- EXPORT_SYMBOL(bcm2838_dma40_memcpy);
- static const struct of_device_id bcm2835_dma_of_match[] = {
--      { .compatible = "brcm,bcm2835-dma", },
-+      { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
-+      { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
-       {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-@@ -999,6 +1178,8 @@ static int bcm2835_dma_probe(struct plat
-       int irq_flags;
-       uint32_t chans_available;
-       char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
-+      const struct of_device_id *of_id;
-+      int chan_count, chan_start, chan_end;
-       if (!pdev->dev.dma_mask)
-               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
-@@ -1020,9 +1201,13 @@ static int bcm2835_dma_probe(struct plat
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
--      rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
--      if (rc)
--              dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
-+
-+      /* The set of channels can be split across multiple instances. */
-+      chan_start = ((u32)(uintptr_t)base / BCM2835_DMA_CHAN_SIZE) & 0xf;
-+      base -= BCM2835_DMA_CHAN(chan_start);
-+      chan_count = resource_size(res) / BCM2835_DMA_CHAN_SIZE;
-+      chan_end = min(chan_start + chan_count,
-+                       BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
-       od->base = base;
-@@ -1059,6 +1244,14 @@ static int bcm2835_dma_probe(struct plat
-               return -ENOMEM;
-       }
-+      of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
-+      if (!of_id) {
-+              dev_err(&pdev->dev, "Failed to match compatible string\n");
-+              return -EINVAL;
-+      }
-+
-+      od->cfg_data = of_id->data;
-+
-       /* Request DMA channel mask from device tree */
-       if (of_property_read_u32(pdev->dev.of_node,
-                       "brcm,dma-channel-mask",
-@@ -1068,18 +1261,34 @@ static int bcm2835_dma_probe(struct plat
-               goto err_no_dma;
-       }
--      /* Channel 0 is used by the legacy API */
--      chans_available &= ~BCM2835_DMA_BULK_MASK;
-+      /* One channel is reserved for the legacy API */
-+      if (chans_available & BCM2835_DMA_BULK_MASK) {
-+              rc = bcm_dmaman_probe(pdev, base,
-+                                    chans_available & BCM2835_DMA_BULK_MASK);
-+              if (rc)
-+                      dev_err(&pdev->dev,
-+                              "Failed to initialize the legacy API\n");
-+
-+              chans_available &= ~BCM2835_DMA_BULK_MASK;
-+      }
--      /* We can't use channels 11-13 yet */
--      chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+      /* And possibly one for the 40-bit DMA memcpy API */
-+      if (chans_available & od->cfg_data->chan_40bit_mask &
-+          BIT(BCM2838_DMA_MEMCPY_CHAN)) {
-+              memcpy_parent = od;
-+              memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
-+              memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
-+                                              sizeof(*memcpy_scb),
-+                                              &memcpy_scb_dma, GFP_KERNEL);
-+              if (!memcpy_scb)
-+                      dev_warn(&pdev->dev,
-+                               "Failed to allocated memcpy scb\n");
--      /* Grab channel 14 for the 40-bit DMA memcpy */
--      chans_available &= ~BIT(14);
--      memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+              chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
-+      }
-       /* get irqs for each channel that we support */
--      for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+      for (i = chan_start; i < chan_end; i++) {
-               /* skip masked out channels */
-               if (!(chans_available & (1 << i))) {
-                       irq[i] = -1;
-@@ -1102,13 +1311,17 @@ static int bcm2835_dma_probe(struct plat
-               irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
-       }
-+      chan_count = 0;
-+
-       /* get irqs for each channel */
--      for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+      for (i = chan_start; i < chan_end; i++) {
-               /* skip channels without irq */
-               if (irq[i] < 0)
-                       continue;
-               /* check if there are other channels that also use this irq */
-+              /* FIXME: This will fail if interrupts are shared across
-+                 instances */
-               irq_flags = 0;
-               for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
-                       if ((i != j) && (irq[j] == irq[i])) {
-@@ -1120,9 +1333,10 @@ static int bcm2835_dma_probe(struct plat
-               rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
-               if (rc)
-                       goto err_no_dma;
-+              chan_count++;
-       }
--      dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
-+      dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", chan_count);
-       /* Device-tree DMA controller registration */
-       rc = of_dma_controller_register(pdev->dev.of_node,
-@@ -1154,6 +1368,13 @@ static int bcm2835_dma_remove(struct pla
-       bcm_dmaman_remove(pdev);
-       dma_async_device_unregister(&od->ddev);
-+      if (memcpy_parent == od) {
-+              dma_free_coherent(&pdev->dev, sizeof(*memcpy_scb), memcpy_scb,
-+                                memcpy_scb_dma);
-+              memcpy_parent = NULL;
-+              memcpy_scb = NULL;
-+              memcpy_chan = NULL;
-+      }
-       bcm2835_dma_free(od);
-       return 0;
---- a/drivers/pci/controller/pcie-brcmstb-bounce.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -91,7 +91,7 @@ struct dmabounce_device_info {
- static struct dmabounce_device_info *g_dmabounce_device_info;
--extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern int bcm2838_dma40_memcpy_init(void);
- extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
- #ifdef STATS
-@@ -465,9 +465,9 @@ static const struct dma_map_ops dmabounc
-       .dma_supported          = dmabounce_dma_supported,
- };
--int brcm_pcie_bounce_register_dev(struct device *dev,
--                                unsigned long buffer_size,
--                                dma_addr_t threshold)
-+int brcm_pcie_bounce_init(struct device *dev,
-+                        unsigned long buffer_size,
-+                        dma_addr_t threshold)
- {
-       struct dmabounce_device_info *device_info;
-       int ret;
-@@ -476,9 +476,9 @@ int brcm_pcie_bounce_register_dev(struct
-       if (g_dmabounce_device_info)
-               return -EBUSY;
--      ret = bcm2838_dma40_memcpy_init(dev);
-+      ret = bcm2838_dma40_memcpy_init();
-       if (ret)
--          return ret;
-+              return ret;
-       device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-       if (!device_info) {
-@@ -509,9 +509,8 @@ int brcm_pcie_bounce_register_dev(struct
-                device_create_file(dev, &dev_attr_dmabounce_stats));
-       g_dmabounce_device_info = device_info;
--      set_dma_ops(dev, &dmabounce_ops);
--      dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+      dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-                buffer_size / 1024, &threshold);
-       return 0;
-@@ -520,14 +519,13 @@ int brcm_pcie_bounce_register_dev(struct
-       kfree(device_info);
-       return ret;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
--void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+void brcm_pcie_bounce_uninit(struct device *dev)
- {
-       struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-       g_dmabounce_device_info = NULL;
--      set_dma_ops(dev, NULL);
-       if (!device_info) {
-               dev_warn(dev,
-@@ -548,10 +546,16 @@ void brcm_pcie_bounce_unregister_dev(str
-                        device_remove_file(dev, &dev_attr_dmabounce_stats));
-       kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+      set_dma_ops(dev, &dmabounce_ops);
--      dev_info(dev, "dmabounce: device unregistered\n");
-+      return 0;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
- MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
- MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -8,21 +8,26 @@
- #ifdef CONFIG_ARM
--int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
--                                dma_addr_t threshold);
--
--int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
-+                        dma_addr_t threshold);
-+int brcm_pcie_bounce_uninit(struct device *dev);
-+int brcm_pcie_bounce_register_dev(struct device *dev);
- #else
--static inline int brcm_pcie_bounce_register_dev(struct device *dev,
--                                              unsigned long buffer_size,
--                                              dma_addr_t threshold)
-+static inline int brcm_pcie_bounce_init(struct device *dev,
-+                                      unsigned long buffer_size,
-+                                      dma_addr_t threshold)
-+{
-+      return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_uninit(struct device *dev)
- {
-       return 0;
- }
--static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev)
- {
-       return 0;
- }
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -644,6 +644,7 @@ static void brcm_set_dma_ops(struct devi
- static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-                                      unsigned int val);
-+
- static int brcmstb_platform_notifier(struct notifier_block *nb,
-                                    unsigned long event, void *__dev)
- {
-@@ -657,12 +658,11 @@ static int brcmstb_platform_notifier(str
-                   strcmp(dev->kobj.name, rc_name)) {
-                       int ret;
--                      ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
--                                                          (dma_addr_t)bounce_threshold);
-+                      ret = brcm_pcie_bounce_register_dev(dev);
-                       if (ret) {
-                               dev_err(dev,
-                                       "brcm_pcie_bounce_register_dev() failed: %d\n",
--                              ret);
-+                                      ret);
-                               return ret;
-                       }
-               }
-@@ -675,8 +675,6 @@ static int brcmstb_platform_notifier(str
-                       brcm_pcie_perst_set(g_pcie, 1);
-                       msleep(100);
-                       brcm_pcie_perst_set(g_pcie, 0);
--              } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
--                      brcm_pcie_bounce_unregister_dev(dev);
-               }
-               return NOTIFY_OK;
-@@ -1712,6 +1710,7 @@ static int brcm_pcie_probe(struct platfo
-       void __iomem *base;
-       struct pci_host_bridge *bridge;
-       struct pci_bus *child;
-+      extern unsigned long max_pfn;
-       bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-       if (!bridge)
-@@ -1747,6 +1746,20 @@ static int brcm_pcie_probe(struct platfo
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-+      /* To Do: Add hardware check if this ever gets fixed */
-+      if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+              int ret;
-+              ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
-+                                          (dma_addr_t)bounce_threshold);
-+              if (ret) {
-+                      if (ret != -EPROBE_DEFER)
-+                              dev_err(&pdev->dev,
-+                                      "could not init bounce buffers: %d\n",
-+                                      ret);
-+                      return ret;
-+              }
-+      }
-+
-       pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-       if (IS_ERR(pcie->clk)) {
-               dev_warn(&pdev->dev, "could not get clock\n");
diff --git a/target/linux/bcm27xx/patches-5.4/950-0278-pcie-brcmstb-Don-t-set-DMA-ops-for-root-complex.patch b/target/linux/bcm27xx/patches-5.4/950-0278-pcie-brcmstb-Don-t-set-DMA-ops-for-root-complex.patch
deleted file mode 100644 (file)
index 91ca640..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From 510a127017a0aada2734dbf57d25aaa0189198ff Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 7 Aug 2019 17:19:33 +0100
-Subject: [PATCH] pcie-brcmstb: Don't set DMA ops for root complex
-
-A change to arm_get_dma_map_ops has stopped get_dma_ops from working
-on the root complex, causing an error to be logged. However, there is
-no need to override the DMA ops in that case, so skip it and
-eliminate the error message.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -665,8 +665,8 @@ static int brcmstb_platform_notifier(str
-                                       ret);
-                               return ret;
-                       }
-+                      brcm_set_dma_ops(dev);
-               }
--              brcm_set_dma_ops(dev);
-               return NOTIFY_OK;
-       case BUS_NOTIFY_DEL_DEVICE:
diff --git a/target/linux/bcm27xx/patches-5.4/950-0283-Ported-pcie-brcmstb-bounce-buffer-implementation-to-.patch b/target/linux/bcm27xx/patches-5.4/950-0283-Ported-pcie-brcmstb-bounce-buffer-implementation-to-.patch
deleted file mode 100644 (file)
index aa8d052..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-From 60f3db31d4cb785befed715b80c430f60f647701 Mon Sep 17 00:00:00 2001
-From: yaroslavros <yaroslavros@gmail.com>
-Date: Wed, 14 Aug 2019 15:22:55 +0100
-Subject: [PATCH] Ported pcie-brcmstb bounce buffer implementation to
- ARM64. (#3144)
-
-Ported pcie-brcmstb bounce buffer implementation to ARM64.
-This enables full 4G RAM usage on Raspberry Pi in 64-bit mode.
-
-Signed-off-by: Yaroslav Rosomakho <yaroslavros@gmail.com>
----
- arch/arm64/mm/dma-mapping.c                   |  29 +
- drivers/pci/controller/Makefile               |   3 +
- drivers/pci/controller/pcie-brcmstb-bounce.h  |   2 +-
- .../pci/controller/pcie-brcmstb-bounce64.c    | 569 ++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb.c         |  32 +-
- 5 files changed, 610 insertions(+), 25 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce64.c
-
---- a/arch/arm64/mm/dma-mapping.c
-+++ b/arch/arm64/mm/dma-mapping.c
-@@ -31,6 +31,35 @@ void arch_dma_prep_coherent(struct page
- }
- #ifdef CONFIG_IOMMU_DMA
-+static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
-+                                    struct page *page, size_t size)
-+{
-+      int ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
-+
-+      if (!ret)
-+              sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
-+
-+      return ret;
-+}
-+
-+static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
-+                            unsigned long pfn, size_t size)
-+{
-+      int ret = -ENXIO;
-+      unsigned long nr_vma_pages = vma_pages(vma);
-+      unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-+      unsigned long off = vma->vm_pgoff;
-+
-+      if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
-+              ret = remap_pfn_range(vma, vma->vm_start,
-+                                    pfn + off,
-+                                    vma->vm_end - vma->vm_start,
-+                                    vma->vm_page_prot);
-+      }
-+
-+      return ret;
-+}
-+
- void arch_teardown_dma_ops(struct device *dev)
- {
-       dev->dma_ops = NULL;
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -33,6 +33,9 @@ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcms
- ifdef CONFIG_ARM
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
- endif
-+ifdef CONFIG_ARM64
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce64.o
-+endif
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -6,7 +6,7 @@
- #ifndef _PCIE_BRCMSTB_BOUNCE_H
- #define _PCIE_BRCMSTB_BOUNCE_H
--#ifdef CONFIG_ARM
-+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
- int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
-                         dma_addr_t threshold);
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -0,0 +1,569 @@
-+/*
-+ *  This code started out as a version of arch/arm/common/dmabounce.c,
-+ *  modified to cope with highmem pages. Now it has been changed heavily -
-+ *  it now preallocates a large block (currently 4MB) and carves it up
-+ *  sequentially in ring fashion, and DMA is used to copy the data - to the
-+ *  point where very little of the original remains.
-+ *
-+ *  Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ *  Original version by Brad Parker (brad@heeltoe.com)
-+ *  Re-written by Christopher Hoover <ch@murgatroid.com>
-+ *  Made generic by Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ *  Copyright (C) 2002 Hewlett Packard Company.
-+ *  Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ *  This program is free software; you can redistribute it and/or
-+ *  modify it under the terms of the GNU General Public License
-+ *  version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-direct.h>
-+#include <linux/dma-noncoherent.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+#include <linux/swiotlb.h>
-+
-+#include <asm/cacheflush.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+      struct list_head node;
-+
-+      /* original request */
-+      size_t          size;
-+      int             direction;
-+
-+      struct dmabounce_pool *pool;
-+      void            *safe;
-+      dma_addr_t      unsafe_dma_addr;
-+      dma_addr_t      safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+      unsigned long   pages;
-+      void            *virt_addr;
-+      dma_addr_t      dma_addr;
-+      unsigned long   *alloc_map;
-+      unsigned long   alloc_pos;
-+      spinlock_t      lock;
-+      struct device   *dev;
-+      unsigned long   num_pages;
-+#ifdef STATS
-+      size_t          max_size;
-+      unsigned long   num_bufs;
-+      unsigned long   max_bufs;
-+      unsigned long   max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+      struct device *dev;
-+      dma_addr_t threshold;
-+      struct list_head safe_buffers;
-+      struct dmabounce_pool pool;
-+      rwlock_t lock;
-+#ifdef STATS
-+      unsigned long map_count;
-+      unsigned long unmap_count;
-+      unsigned long sync_dev_count;
-+      unsigned long sync_cpu_count;
-+      unsigned long fail_count;
-+      int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(void);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+      return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+              device_info->map_count,
-+              device_info->unmap_count,
-+              device_info->sync_dev_count,
-+              device_info->sync_cpu_count,
-+              device_info->fail_count,
-+              device_info->pool.max_size,
-+              device_info->pool.num_bufs,
-+              device_info->pool.max_bufs,
-+              device_info->pool.num_pages * PAGE_SIZE,
-+              device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+                       unsigned long buffer_size)
-+{
-+      int ret = -ENOMEM;
-+      pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+      pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+      if (!pool->alloc_map)
-+              goto err_bitmap;
-+      pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+                                           &pool->dma_addr, GFP_KERNEL);
-+      if (!pool->virt_addr)
-+              goto err_dmabuf;
-+
-+      pool->alloc_pos = 0;
-+      spin_lock_init(&pool->lock);
-+      pool->dev = dev;
-+      pool->num_pages = 0;
-+
-+      DO_STATS(pool->max_size = 0);
-+      DO_STATS(pool->num_bufs = 0);
-+      DO_STATS(pool->max_bufs = 0);
-+      DO_STATS(pool->max_pages = 0);
-+
-+      return  0;
-+
-+err_dmabuf:
-+      bitmap_free(pool->alloc_map);
-+err_bitmap:
-+      return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+      dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+                        pool->dma_addr);
-+
-+      bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+                        dma_addr_t *dmaaddrp)
-+{
-+      unsigned long pages;
-+      unsigned long flags;
-+      unsigned long pos;
-+
-+      pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+      DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+      spin_lock_irqsave(&pool->lock, flags);
-+      pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+                                       pool->alloc_pos, pages, 0);
-+      /* If not found, try from the start */
-+      if (pos >= pool->pages && pool->alloc_pos)
-+              pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+                                               0, pages, 0);
-+
-+      if (pos >= pool->pages) {
-+              spin_unlock_irqrestore(&pool->lock, flags);
-+              return NULL;
-+      }
-+
-+      bitmap_set(pool->alloc_map, pos, pages);
-+      pool->alloc_pos = (pos + pages) % pool->pages;
-+      pool->num_pages += pages;
-+
-+      DO_STATS(pool->num_bufs++);
-+      DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+      DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+      spin_unlock_irqrestore(&pool->lock, flags);
-+
-+      *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+      return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+      unsigned long pages;
-+      unsigned long flags;
-+      unsigned long pos;
-+
-+      pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+      pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+      BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+      spin_lock_irqsave(&pool->lock, flags);
-+      bitmap_clear(pool->alloc_map, pos, pages);
-+      pool->num_pages -= pages;
-+      if (pool->num_pages == 0)
-+              pool->alloc_pos = 0;
-+      DO_STATS(pool->num_bufs--);
-+      spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+                dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+      struct dmabounce_pool *pool = &device_info->pool;
-+      struct device *dev = device_info->dev;
-+      unsigned long flags;
-+
-+      /*
-+       * Although one might expect this to be called in thread context,
-+       * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+       * was previously used to select the appropriate allocation mode,
-+       * but this is unsafe.
-+       */
-+      buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+      if (!buf) {
-+              dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+              return NULL;
-+      }
-+
-+      buf->unsafe_dma_addr = dma_addr;
-+      buf->size = size;
-+      buf->direction = dir;
-+      buf->pool = pool;
-+
-+      buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+      if (!buf->safe) {
-+              dev_warn(dev,
-+                       "%s: could not alloc dma memory (size=%zu)\n",
-+                       __func__, size);
-+              kfree(buf);
-+              return NULL;
-+      }
-+
-+      write_lock_irqsave(&device_info->lock, flags);
-+      list_add(&buf->node, &device_info->safe_buffers);
-+      write_unlock_irqrestore(&device_info->lock, flags);
-+
-+      return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+               dma_addr_t safe_dma_addr)
-+{
-+      struct safe_buffer *b, *rb = NULL;
-+      unsigned long flags;
-+
-+      read_lock_irqsave(&device_info->lock, flags);
-+
-+      list_for_each_entry(b, &device_info->safe_buffers, node)
-+              if (b->safe_dma_addr <= safe_dma_addr &&
-+                  b->safe_dma_addr + b->size > safe_dma_addr) {
-+                      rb = b;
-+                      break;
-+              }
-+
-+      read_unlock_irqrestore(&device_info->lock, flags);
-+      return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+               struct safe_buffer *buf)
-+{
-+      unsigned long flags;
-+
-+      write_lock_irqsave(&device_info->lock, flags);
-+      list_del(&buf->node);
-+      write_unlock_irqrestore(&device_info->lock, flags);
-+
-+      bounce_free(buf->pool, buf->safe, buf->size);
-+
-+      kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+      if (!dev || !g_dmabounce_device_info)
-+              return NULL;
-+      if (dma_mapping_error(dev, dma_addr)) {
-+              dev_err(dev, "Trying to %s invalid mapping\n", where);
-+              return NULL;
-+      }
-+      return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+         enum dma_data_direction dir, unsigned long attrs)
-+{
-+      BUG_ON(buf->size != size);
-+      BUG_ON(buf->direction != dir);
-+
-+      dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+              (u64)buf->safe_dma_addr);
-+
-+      if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+          !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+              bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+                                   size);
-+
-+      return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+           enum dma_data_direction dir, unsigned long attrs)
-+{
-+      BUG_ON(buf->size != size);
-+      BUG_ON(buf->direction != dir);
-+
-+      if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+          !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+              dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+                      (u64)buf->unsafe_dma_addr);
-+
-+              bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+                                   size);
-+      }
-+      return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range.  if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+                 size_t size, enum dma_data_direction dir,
-+                 unsigned long attrs)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+      dma_addr_t dma_addr;
-+
-+      dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
-+
-+      dma_direct_sync_single_for_device(dev, dma_addr, size, dir);
-+        if (!dev_is_dma_coherent(dev))
-+              __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+      if (device_info && (dma_addr + size) > device_info->threshold) {
-+              struct safe_buffer *buf;
-+
-+              buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+              if (!buf) {
-+                      DO_STATS(device_info->fail_count++);
-+                      return (~(dma_addr_t)0x0);
-+              }
-+
-+              DO_STATS(device_info->map_count++);
-+
-+              dma_addr = map_single(dev, buf, size, dir, attrs);
-+      }
-+      return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer.  (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+                   enum dma_data_direction dir, unsigned long attrs)
-+{
-+      struct safe_buffer *buf;
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->unmap_count++);
-+              dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+              free_safe_buffer(g_dmabounce_device_info, buf);
-+      }
-+
-+        if (!dev_is_dma_coherent(dev))
-+              __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+      dma_direct_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+                        enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+
-+        dma_direct_sync_single_for_device(dev, dma_addr, size, dir);
-+        if (!dev_is_dma_coherent(dev))
-+                __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+              map_single(dev, buf, size, dir, 0);
-+      }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+                     size_t size, enum dma_data_direction dir)
-+{
-+      struct safe_buffer *buf;
-+
-+      buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+      if (buf) {
-+              DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+              dma_addr = unmap_single(dev, buf, size, dir, 0);
-+      }
-+
-+        if (!dev_is_dma_coherent(dev))
-+                __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+        dma_direct_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+      if (g_dmabounce_device_info)
-+              return 0;
-+
-+      return dma_direct_supported(dev, dma_mask);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+      .alloc                  = dma_direct_alloc,
-+      .free                   = dma_direct_free,
-+      .map_page               = dmabounce_map_page,
-+      .unmap_page             = dmabounce_unmap_page,
-+      .sync_single_for_cpu    = dmabounce_sync_for_cpu,
-+      .sync_single_for_device = dmabounce_sync_for_device,
-+      .map_sg                 = dma_direct_map_sg,
-+      .unmap_sg               = dma_direct_unmap_sg,
-+      .sync_sg_for_cpu        = dma_direct_sync_sg_for_cpu,
-+      .sync_sg_for_device     = dma_direct_sync_sg_for_device,
-+      .dma_supported          = dmabounce_dma_supported,
-+};
-+
-+int brcm_pcie_bounce_init(struct device *dev,
-+                        unsigned long buffer_size,
-+                        dma_addr_t threshold)
-+{
-+      struct dmabounce_device_info *device_info;
-+      int ret;
-+
-+      /* Only support a single client */
-+      if (g_dmabounce_device_info)
-+              return -EBUSY;
-+
-+      ret = bcm2838_dma40_memcpy_init();
-+      if (ret)
-+              return ret;
-+
-+      device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+      if (!device_info) {
-+              dev_err(dev,
-+                      "Could not allocated dmabounce_device_info\n");
-+              return -ENOMEM;
-+      }
-+
-+      ret = bounce_create(&device_info->pool, dev, buffer_size);
-+      if (ret) {
-+              dev_err(dev,
-+                      "dmabounce: could not allocate %ld byte DMA pool\n",
-+                      buffer_size);
-+              goto err_bounce;
-+      }
-+
-+      device_info->dev = dev;
-+      device_info->threshold = threshold;
-+      INIT_LIST_HEAD(&device_info->safe_buffers);
-+      rwlock_init(&device_info->lock);
-+
-+      DO_STATS(device_info->map_count = 0);
-+      DO_STATS(device_info->unmap_count = 0);
-+      DO_STATS(device_info->sync_dev_count = 0);
-+      DO_STATS(device_info->sync_cpu_count = 0);
-+      DO_STATS(device_info->fail_count = 0);
-+      DO_STATS(device_info->attr_res =
-+               device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+      g_dmabounce_device_info = device_info;
-+
-+      dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+               buffer_size / 1024, &threshold);
-+
-+      return 0;
-+
-+ err_bounce:
-+      kfree(device_info);
-+      return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
-+
-+void brcm_pcie_bounce_uninit(struct device *dev)
-+{
-+      struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+      g_dmabounce_device_info = NULL;
-+
-+      if (!device_info) {
-+              dev_warn(dev,
-+                       "Never registered with dmabounce but attempting"
-+                       "to unregister!\n");
-+              return;
-+      }
-+
-+      if (!list_empty(&device_info->safe_buffers)) {
-+              dev_err(dev,
-+                      "Removing from dmabounce with pending buffers!\n");
-+              BUG();
-+      }
-+
-+      bounce_destroy(&device_info->pool);
-+
-+      DO_STATS(if (device_info->attr_res == 0)
-+                       device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+      kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+      set_dma_ops(dev, &dmabounce_ops);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -611,28 +611,6 @@ static const struct dma_map_ops brcm_dma
- static void brcm_set_dma_ops(struct device *dev)
- {
--      int ret;
--
--      if (IS_ENABLED(CONFIG_ARM64)) {
--              /*
--               * We are going to invoke get_dma_ops().  That
--               * function, at this point in time, invokes
--               * get_arch_dma_ops(), and for ARM64 that function
--               * returns a pointer to dummy_dma_ops.  So then we'd
--               * like to call arch_setup_dma_ops(), but that isn't
--               * exported.  Instead, we call of_dma_configure(),
--               * which is exported, and this calls
--               * arch_setup_dma_ops().  Once we do this the call to
--               * get_dma_ops() will work properly because
--               * dev->dma_ops will be set.
--               */
--              ret = of_dma_configure(dev, dev->of_node, true);
--              if (ret) {
--                      dev_err(dev, "of_dma_configure() failed: %d\n", ret);
--                      return;
--              }
--      }
--
-       arch_dma_ops = get_dma_ops(dev);
-       if (!arch_dma_ops) {
-               dev_err(dev, "failed to get arch_dma_ops\n");
-@@ -651,12 +629,12 @@ static int brcmstb_platform_notifier(str
-       extern unsigned long max_pfn;
-       struct device *dev = __dev;
-       const char *rc_name = "0000:00:00.0";
-+      int ret;
-       switch (event) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
-                   strcmp(dev->kobj.name, rc_name)) {
--                      int ret;
-                       ret = brcm_pcie_bounce_register_dev(dev);
-                       if (ret) {
-@@ -665,8 +643,14 @@ static int brcmstb_platform_notifier(str
-                                       ret);
-                               return ret;
-                       }
--                      brcm_set_dma_ops(dev);
-+              } else if (IS_ENABLED(CONFIG_ARM64)) {
-+                      ret = of_dma_configure(dev, dev->of_node, true);
-+                      if (ret) {
-+                              dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+                              return ret;
-+                      }
-               }
-+              brcm_set_dma_ops(dev);
-               return NOTIFY_OK;
-       case BUS_NOTIFY_DEL_DEVICE:
diff --git a/target/linux/bcm27xx/patches-5.4/950-0311-media-dt-bindings-Add-binding-for-the-Sony-IMX219-se.patch b/target/linux/bcm27xx/patches-5.4/950-0311-media-dt-bindings-Add-binding-for-the-Sony-IMX219-se.patch
deleted file mode 100644 (file)
index 4fb64f5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-From 7bd5937663a13ad17a04d8ca8ba1503d492cf42b Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 28 Aug 2019 13:34:30 +0100
-Subject: [PATCH] media: dt-bindings: Add binding for the Sony IMX219
- sensor
-
-The IMX219 is an 8MPix CSI2 sensor, supporting 2 or 4 data lanes.
-Document the binding for this device.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../devicetree/bindings/media/i2c/imx219.txt  | 59 +++++++++++++++++++
- 1 file changed, 59 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/imx219.txt
-@@ -0,0 +1,59 @@
-+* Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
-+
-+The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor with
-+an active array size of 3280H x 2464V. It is programmable through I2C
-+interface. The I2C address is fixed to 0x10 as per sensor data sheet.
-+Image data is sent through MIPI CSI-2, which is configured as either 2 or 4
-+data lanes.
-+
-+Required Properties:
-+- compatible: value should be "sony,imx219" for imx219 sensor
-+- reg: I2C bus address of the device
-+- clocks: reference to the xclk input clock.
-+- clock-names: should be "xclk".
-+- DOVDD-supply: Digital I/O voltage supply, 1.8 volts
-+- AVDD-supply: Analog voltage supply, 2.8 volts
-+- DVDD-supply: Digital core voltage supply, 1.2 volts
-+
-+Optional Properties:
-+- xclr-gpios: reference to the GPIO connected to the xclr pin, if any. Must be
-+            released after all supplies are applied.
-+            This is an active high signal to the imx219.
-+
-+The imx219 device node should contain one 'port' child node with
-+an 'endpoint' subnode. For further reading on port node refer to
-+Documentation/devicetree/bindings/media/video-interfaces.txt.
-+
-+Endpoint node required properties for CSI-2 connection are:
-+- remote-endpoint: a phandle to the bus receiver's endpoint node.
-+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
-+- data-lanes: should be set to <1 2>, or  <1 2 3 4> (two or four lane CSI-2
-+  supported)
-+
-+Example:
-+      sensor@10 {
-+              compatible = "sony,imx219";
-+              reg = <0x10>;
-+              #address-cells = <1>;
-+              #size-cells = <0>;
-+              clocks = <&imx219_clk>;
-+              clock-names = "xclk";
-+              xclr-gpios = <&gpio_sensor 0 0>;
-+              DOVDD-supply = <&vgen4_reg>; /* 1.8v */
-+              AVDD-supply = <&vgen3_reg>;  /* 2.8v */
-+              DVDD-supply = <&vgen2_reg>;  /* 1.2v */
-+
-+              imx219_clk: camera-clk {
-+                      compatible = "fixed-clock";
-+                      #clock-cells = <0>;
-+                      clock-frequency = <24000000>;
-+              };
-+
-+              port {
-+                      sensor_out: endpoint {
-+                              remote-endpoint = <&csiss_in>;
-+                              clock-lanes = <0>;
-+                              data-lanes = <1 2>;
-+                      };
-+              };
-+      };
similarity index 99%
rename from target/linux/bcm27xx/patches-5.4/950-0337-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch
rename to target/linux/bcm27xx/patches-5.4/950-0326-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch
index 5ea4797bcdb197482fd7e990bb08c996869b61a6..71e218d9ecad17967dd3f05be6c506eb3c90d9ce 100644 (file)
@@ -21,7 +21,7 @@ Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
 
 --- a/drivers/media/i2c/Kconfig
 +++ b/drivers/media/i2c/Kconfig
-@@ -850,6 +850,18 @@ config VIDEO_OV13858
+@@ -839,6 +839,18 @@ config VIDEO_OV13858
          This is a Video4Linux2 sensor driver for the OmniVision
          OV13858 camera.
  
diff --git a/target/linux/bcm27xx/patches-5.4/950-0333-pcie-brcmstb-bounce64.c-dev_err-dev_info-for-info-me.patch b/target/linux/bcm27xx/patches-5.4/950-0333-pcie-brcmstb-bounce64.c-dev_err-dev_info-for-info-me.patch
deleted file mode 100644 (file)
index 170c2f3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 2340a88a493d750dc3fcfa48de880fc4b8e479d2 Mon Sep 17 00:00:00 2001
-From: Floris Bos <bos@je-eigen-domein.nl>
-Date: Fri, 4 Oct 2019 16:41:30 +0200
-Subject: [PATCH] pcie-brcmstb-bounce64.c: dev_err() -> dev_info() for
- info messages
-
-"dmabounce: initialised" is not an error, so do not log it as such.
-Prevents screen polution on OS with "quiet" as kernel parameter.
-
-Closes #3266
----
- drivers/pci/controller/pcie-brcmstb-bounce64.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -517,7 +517,7 @@ int brcm_pcie_bounce_init(struct device
-       g_dmabounce_device_info = device_info;
--      dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+      dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-                buffer_size / 1024, &threshold);
-       return 0;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0384-pcie-brcmstb-Eliminate-arch_dma_ops-error-message.patch b/target/linux/bcm27xx/patches-5.4/950-0384-pcie-brcmstb-Eliminate-arch_dma_ops-error-message.patch
deleted file mode 100644 (file)
index ee7cf0e..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-From 27cf0ad95cdf30f52a5fc6c69014a0d7bf5a1222 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 8 Jan 2020 17:21:09 +0000
-Subject: [PATCH] pcie-brcmstb: Eliminate arch_dma_ops error message
-
-The driver attempts to set the dma_ops for the root complex, but doing
-so causes an error message and only the end points need it. Fix the
-error by making the code specific to the end point case.
-
-Also copy some cosmetic tidy-ups from 5.5.y.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 43 ++++++++++++++-------------
- 1 file changed, 22 insertions(+), 21 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -633,16 +633,17 @@ static int brcmstb_platform_notifier(str
-       switch (event) {
-       case BUS_NOTIFY_ADD_DEVICE:
--              if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
--                  strcmp(dev->kobj.name, rc_name)) {
--
--                      ret = brcm_pcie_bounce_register_dev(dev);
--                      if (ret) {
--                              dev_err(dev,
--                                      "brcm_pcie_bounce_register_dev() failed: %d\n",
--                                      ret);
--                              return ret;
-+              if (strcmp(dev->kobj.name, rc_name)) {
-+                      if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+                              ret = brcm_pcie_bounce_register_dev(dev);
-+                              if (ret) {
-+                                      dev_err(dev,
-+                                              "brcm_pcie_bounce_register_dev() failed: %d\n",
-+                                              ret);
-+                                      return ret;
-+                              }
-                       }
-+                      brcm_set_dma_ops(dev);
-               } else if (IS_ENABLED(CONFIG_ARM64)) {
-                       ret = of_dma_configure(dev, dev->of_node, true);
-                       if (ret) {
-@@ -650,7 +651,6 @@ static int brcmstb_platform_notifier(str
-                               return ret;
-                       }
-               }
--              brcm_set_dma_ops(dev);
-               return NOTIFY_OK;
-       case BUS_NOTIFY_DEL_DEVICE:
-@@ -1685,7 +1685,8 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
- static int brcm_pcie_probe(struct platform_device *pdev)
- {
--      struct device_node *dn = pdev->dev.of_node, *msi_dn;
-+      struct device *dev = &pdev->dev;
-+      struct device_node *dn = dev->of_node, *msi_dn;
-       const struct of_device_id *of_id;
-       const struct pcie_cfg_data *data;
-       int ret;
-@@ -1696,7 +1697,7 @@ static int brcm_pcie_probe(struct platfo
-       struct pci_bus *child;
-       extern unsigned long max_pfn;
--      bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-+      bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
-       if (!bridge)
-               return -ENOMEM;
-@@ -1705,7 +1706,7 @@ static int brcm_pcie_probe(struct platfo
-       of_id = of_match_node(brcm_pcie_match, dn);
-       if (!of_id) {
--              dev_err(&pdev->dev, "failed to look up compatible string\n");
-+              dev_err(dev, "failed to look up compatible string\n");
-               return -EINVAL;
-       }
-@@ -1715,7 +1716,7 @@ static int brcm_pcie_probe(struct platfo
-       pcie->max_burst_size = data->max_burst_size;
-       pcie->type = data->type;
-       pcie->dn = dn;
--      pcie->dev = &pdev->dev;
-+      pcie->dev = dev;
-       /* We use the domain number as our controller number */
-       pcie->id = of_get_pci_domain_nr(dn);
-@@ -1726,18 +1727,18 @@ static int brcm_pcie_probe(struct platfo
-       if (!res)
-               return -EINVAL;
--      base = devm_ioremap_resource(&pdev->dev, res);
-+      base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-       /* To Do: Add hardware check if this ever gets fixed */
-       if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-               int ret;
--              ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
-+              ret = brcm_pcie_bounce_init(dev, bounce_buffer,
-                                           (dma_addr_t)bounce_threshold);
-               if (ret) {
-                       if (ret != -EPROBE_DEFER)
--                              dev_err(&pdev->dev,
-+                              dev_err(dev,
-                                       "could not init bounce buffers: %d\n",
-                                       ret);
-                       return ret;
-@@ -1746,7 +1747,7 @@ static int brcm_pcie_probe(struct platfo
-       pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-       if (IS_ERR(pcie->clk)) {
--              dev_warn(&pdev->dev, "could not get clock\n");
-+              dev_warn(dev, "could not get clock\n");
-               pcie->clk = NULL;
-       }
-       pcie->base = base;
-@@ -1756,7 +1757,7 @@ static int brcm_pcie_probe(struct platfo
-       pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
--      ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
-+      ret = irq_of_parse_and_map(dev->of_node, 0);
-       if (ret == 0)
-               /* keep going, as we don't use this intr yet */
-               dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
-@@ -1770,7 +1771,7 @@ static int brcm_pcie_probe(struct platfo
-       ret = clk_prepare_enable(pcie->clk);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
--                      dev_err(&pdev->dev, "could not enable clock\n");
-+                      dev_err(dev, "could not enable clock\n");
-               return ret;
-       }
-@@ -1797,7 +1798,7 @@ static int brcm_pcie_probe(struct platfo
-       }
-       list_splice_init(&pcie->resources, &bridge->windows);
--      bridge->dev.parent = &pdev->dev;
-+      bridge->dev.parent = dev;
-       bridge->busnr = 0;
-       bridge->ops = &brcm_pcie_ops;
-       bridge->sysdata = pcie;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0421-pcie-brcmstb-Bounce-buffer-support-is-for-BCM2711B0.patch b/target/linux/bcm27xx/patches-5.4/950-0421-pcie-brcmstb-Bounce-buffer-support-is-for-BCM2711B0.patch
deleted file mode 100644 (file)
index 73da382..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-From 58ac2d4474e531300f9f83773aa4d09e95ee2626 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 12 Jul 2019 11:41:25 +0100
-Subject: [PATCH] pcie-brcmstb: Bounce buffer support is for BCM2711B0
-
-Add a new compatible string to identify BCM2711B0, as later revisions
-don't require the bounce buffer support.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 31 +++++++++++++++++++++++----
- 1 file changed, 27 insertions(+), 4 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -206,6 +206,8 @@ enum pcie_type {
-       BCM7435,
-       GENERIC,
-       BCM7278,
-+      BCM2711B0,
-+      BCM2711,
- };
- struct brcm_window {
-@@ -302,6 +304,20 @@ static const int pcie_offsets[] = {
-       [EXT_CFG_DATA]   = 0x8000,
- };
-+static const struct pcie_cfg_data bcm2711b0_cfg = {
-+      .reg_field_info = pcie_reg_field_info,
-+      .offsets        = pcie_offsets,
-+      .max_burst_size = BURST_SIZE_128,
-+      .type           = BCM2711B0,
-+};
-+
-+static const struct pcie_cfg_data bcm2711_cfg = {
-+      .reg_field_info = pcie_reg_field_info,
-+      .offsets        = pcie_offsets,
-+      .max_burst_size = BURST_SIZE_128,
-+      .type           = BCM2711,
-+};
-+
- static const struct pcie_cfg_data bcm7435_cfg = {
-       .reg_field_info = pcie_reg_field_info,
-       .offsets        = pcie_offsets,
-@@ -312,7 +328,7 @@ static const struct pcie_cfg_data bcm743
- static const struct pcie_cfg_data generic_cfg = {
-       .reg_field_info = pcie_reg_field_info,
-       .offsets        = pcie_offsets,
--      .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
-+      .max_burst_size = BURST_SIZE_512,
-       .type           = GENERIC,
- };
-@@ -380,7 +396,7 @@ static unsigned int bounce_buffer = 32*1
- module_param(bounce_buffer, uint, 0644);
- MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
--static unsigned int bounce_threshold = 0xc0000000;
-+static unsigned int bounce_threshold;
- module_param(bounce_threshold, uint, 0644);
- MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
-@@ -1675,6 +1691,8 @@ static int brcm_pcie_remove(struct platf
- }
- static const struct of_device_id brcm_pcie_match[] = {
-+      { .compatible = "brcm,bcm2711b0-pcie", .data = &bcm2711b0_cfg },
-+      { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
-       { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
-       { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
-       { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
-@@ -1731,8 +1749,13 @@ static int brcm_pcie_probe(struct platfo
-       if (IS_ERR(base))
-               return PTR_ERR(base);
--      /* To Do: Add hardware check if this ever gets fixed */
--      if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+      if (!bounce_threshold) {
-+              /* PCIe on BCM2711B0 can only address 3GB */
-+              if (pcie->type == BCM2711B0 || pcie->type == GENERIC)
-+                      bounce_threshold = 0xc0000000;
-+      }
-+
-+      if (bounce_threshold && (max_pfn > (bounce_threshold/PAGE_SIZE))) {
-               int ret;
-               ret = brcm_pcie_bounce_init(dev, bounce_buffer,
-                                           (dma_addr_t)bounce_threshold);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch
new file mode 100644 (file)
index 0000000..4774fd2
--- /dev/null
@@ -0,0 +1,26 @@
+From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Thu, 30 Jan 2020 12:35:44 +0000
+Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when
+ counting transactions
+
+The response block and local state were using u16 and u32 respectively
+to represent transaction id.  When the former would wrap, there is a
+mismatch and subsequent transactions will be marked as failures.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk {
+       /* To be signaled when the response is there */
+       struct completion cmplt;
+-      u16 id;
++      u32 id;
+       u16 length;
+       u8 msg[VC_SM_MAX_MSG_LEN];
diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch
new file mode 100644 (file)
index 0000000..213e8b8
--- /dev/null
@@ -0,0 +1,34 @@
+From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 7 Feb 2020 09:51:31 +0000
+Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff
+
+The timeout_ms parameter specifies in milliseconds how long the kernel
+waits for power-down before issuing a WARN. The default value is 3000 ms.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/README                    | 2 ++
+ arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -821,6 +821,8 @@ Params: gpiopin                 GPIO for
+         input                   Set if the gpio pin should be configured as
+                                 an input.
+         export                  Set to export the configured pin to sysfs
++        timeout_ms              Specify (in ms) how long the kernel waits for
++                                power-down before issuing a WARN (default 3000).
+ Name:   gpio-shutdown
+--- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
+@@ -32,5 +32,6 @@
+               active_low =    <&power_ctrl>,"gpios:8";
+               input =         <&power_ctrl>,"input?";
+               export =        <&power_ctrl>,"export?";
++              timeout_ms =    <&power_ctrl>,"timeout-ms:0";
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch
new file mode 100644 (file)
index 0000000..4b00587
--- /dev/null
@@ -0,0 +1,37 @@
+From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 6 Feb 2020 12:23:15 +0000
+Subject: [PATCH] of: overlay: Correct symbol path fixups
+
+When symbols from overlays are added to the live tree their paths must
+be rebased. The translated symbol is normally the result of joining
+the fragment-relative path (with a leading "/") to the target path
+(either copied directly from the "target-path" property or resolved
+from the phandle). This translation fails when the target is the root
+node (a common case for Raspberry Pi overlays) because the resulting
+path starts with a double slash. For example, if target-path is "/" and
+the fragment adds a node called "newnode", the label associated with
+that node will be assigned the path "//newnode", which can't be found
+in the tree.
+
+Fix the failure case by explicitly replacing a target path of "/" with
+an empty string.
+
+Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/of/overlay.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/of/overlay.c
++++ b/drivers/of/overlay.c
+@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy
+       if (!target_path)
+               return NULL;
+       target_path_len = strlen(target_path);
++      if (!strcmp(target_path, "/"))
++              target_path_len = 0;
+       new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+       if (!new_prop)
diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch
new file mode 100644 (file)
index 0000000..636ad26
--- /dev/null
@@ -0,0 +1,25 @@
+From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 3 Mar 2020 09:43:41 +0000
+Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter
+
+The xtal parameter is targetting the wrong node - fix it.
+
+See: https://github.com/raspberrypi/linux/issues/3156
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
+@@ -32,7 +32,7 @@
+       __overrides__ {
+               int_pin = <&sc16is750>,"interrupts:0";
+               addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name";
+-              xtal = <&sc16is750>,"clock-frequency:0";
++              xtal = <&sc16is750_clk>,"clock-frequency:0";
+       };
+ };
diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-bcm2835-dma-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0441-bcm2835-dma-Correct-SoC-name.patch
deleted file mode 100644 (file)
index fe33168..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-From f498861a16d0b9a189a329080da1aa64d6e9bda7 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:28:57 +0000
-Subject: [PATCH] bcm2835-dma: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "bcm2835-dma: Add proper 40-bit DMA support"
----
- drivers/dma/bcm2835-dma.c | 274 +++++++++++++++++++-------------------
- 1 file changed, 137 insertions(+), 137 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -38,7 +38,7 @@
- #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
- #define BCM2835_DMA_CHAN_NAME_SIZE 8
- #define BCM2835_DMA_BULK_MASK  BIT(0)
--#define BCM2838_DMA_MEMCPY_CHAN 14
-+#define BCM2711_DMA_MEMCPY_CHAN 14
- struct bcm2835_dma_cfg_data {
-       u32     chan_40bit_mask;
-@@ -70,7 +70,7 @@ struct bcm2835_dma_cb {
-       uint32_t pad[2];
- };
--struct bcm2838_dma40_scb {
-+struct bcm2711_dma40_scb {
-       uint32_t ti;
-       uint32_t src;
-       uint32_t srci;
-@@ -200,98 +200,98 @@ struct bcm2835_desc {
- #define MAX_LITE_DMA_LEN (SZ_64K - 4)
- /* 40-bit DMA support */
--#define BCM2838_DMA40_CS      0x00
--#define BCM2838_DMA40_CB      0x04
--#define BCM2838_DMA40_DEBUG   0x0c
--#define BCM2838_DMA40_TI      0x10
--#define BCM2838_DMA40_SRC     0x14
--#define BCM2838_DMA40_SRCI    0x18
--#define BCM2838_DMA40_DEST    0x1c
--#define BCM2838_DMA40_DESTI   0x20
--#define BCM2838_DMA40_LEN     0x24
--#define BCM2838_DMA40_NEXT_CB 0x28
--#define BCM2838_DMA40_DEBUG2  0x2c
--
--#define BCM2838_DMA40_ACTIVE          BIT(0)
--#define BCM2838_DMA40_END             BIT(1)
--#define BCM2838_DMA40_INT             BIT(2)
--#define BCM2838_DMA40_DREQ            BIT(3)  /* DREQ state */
--#define BCM2838_DMA40_RD_PAUSED               BIT(4)  /* Reading is paused */
--#define BCM2838_DMA40_WR_PAUSED               BIT(5)  /* Writing is paused */
--#define BCM2838_DMA40_DREQ_PAUSED     BIT(6)  /* Is paused by DREQ flow control */
--#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7)  /* Waiting for last write */
--#define BCM2838_DMA40_ERR             BIT(10)
--#define BCM2838_DMA40_QOS(x)          (((x) & 0x1f) << 16)
--#define BCM2838_DMA40_PANIC_QOS(x)    (((x) & 0x1f) << 20)
--#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
--#define BCM2838_DMA40_DISDEBUG                BIT(29)
--#define BCM2838_DMA40_ABORT           BIT(30)
--#define BCM2838_DMA40_HALT            BIT(31)
--#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
--                                      BCM2838_DMA40_PANIC_QOS(15) | \
--                                      BCM2838_DMA40_WAIT_FOR_WRITES | \
--                                      BCM2838_DMA40_DISDEBUG))
-+#define BCM2711_DMA40_CS      0x00
-+#define BCM2711_DMA40_CB      0x04
-+#define BCM2711_DMA40_DEBUG   0x0c
-+#define BCM2711_DMA40_TI      0x10
-+#define BCM2711_DMA40_SRC     0x14
-+#define BCM2711_DMA40_SRCI    0x18
-+#define BCM2711_DMA40_DEST    0x1c
-+#define BCM2711_DMA40_DESTI   0x20
-+#define BCM2711_DMA40_LEN     0x24
-+#define BCM2711_DMA40_NEXT_CB 0x28
-+#define BCM2711_DMA40_DEBUG2  0x2c
-+
-+#define BCM2711_DMA40_ACTIVE          BIT(0)
-+#define BCM2711_DMA40_END             BIT(1)
-+#define BCM2711_DMA40_INT             BIT(2)
-+#define BCM2711_DMA40_DREQ            BIT(3)  /* DREQ state */
-+#define BCM2711_DMA40_RD_PAUSED               BIT(4)  /* Reading is paused */
-+#define BCM2711_DMA40_WR_PAUSED               BIT(5)  /* Writing is paused */
-+#define BCM2711_DMA40_DREQ_PAUSED     BIT(6)  /* Is paused by DREQ flow control */
-+#define BCM2711_DMA40_WAITING_FOR_WRITES BIT(7)  /* Waiting for last write */
-+#define BCM2711_DMA40_ERR             BIT(10)
-+#define BCM2711_DMA40_QOS(x)          (((x) & 0x1f) << 16)
-+#define BCM2711_DMA40_PANIC_QOS(x)    (((x) & 0x1f) << 20)
-+#define BCM2711_DMA40_WAIT_FOR_WRITES BIT(28)
-+#define BCM2711_DMA40_DISDEBUG                BIT(29)
-+#define BCM2711_DMA40_ABORT           BIT(30)
-+#define BCM2711_DMA40_HALT            BIT(31)
-+#define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \
-+                                      BCM2711_DMA40_PANIC_QOS(15) | \
-+                                      BCM2711_DMA40_WAIT_FOR_WRITES | \
-+                                      BCM2711_DMA40_DISDEBUG))
- /* Transfer information bits */
--#define BCM2838_DMA40_INTEN           BIT(0)
--#define BCM2838_DMA40_TDMODE          BIT(1) /* 2D-Mode */
--#define BCM2838_DMA40_WAIT_RESP               BIT(2) /* wait for AXI write to be acked */
--#define BCM2838_DMA40_WAIT_RD_RESP    BIT(3) /* wait for AXI read to complete */
--#define BCM2838_DMA40_PER_MAP(x)      ((x & 31) << 9) /* REQ source */
--#define BCM2838_DMA40_S_DREQ          BIT(14) /* enable SREQ for source */
--#define BCM2838_DMA40_D_DREQ          BIT(15) /* enable DREQ for destination */
--#define BCM2838_DMA40_S_WAIT(x)               ((x & 0xff) << 16) /* add DMA read-wait cycles */
--#define BCM2838_DMA40_D_WAIT(x)               ((x & 0xff) << 24) /* add DMA write-wait cycles */
-+#define BCM2711_DMA40_INTEN           BIT(0)
-+#define BCM2711_DMA40_TDMODE          BIT(1) /* 2D-Mode */
-+#define BCM2711_DMA40_WAIT_RESP               BIT(2) /* wait for AXI write to be acked */
-+#define BCM2711_DMA40_WAIT_RD_RESP    BIT(3) /* wait for AXI read to complete */
-+#define BCM2711_DMA40_PER_MAP(x)      ((x & 31) << 9) /* REQ source */
-+#define BCM2711_DMA40_S_DREQ          BIT(14) /* enable SREQ for source */
-+#define BCM2711_DMA40_D_DREQ          BIT(15) /* enable DREQ for destination */
-+#define BCM2711_DMA40_S_WAIT(x)               ((x & 0xff) << 16) /* add DMA read-wait cycles */
-+#define BCM2711_DMA40_D_WAIT(x)               ((x & 0xff) << 24) /* add DMA write-wait cycles */
- /* debug register bits */
--#define BCM2838_DMA40_DEBUG_WRITE_ERR         BIT(0)
--#define BCM2838_DMA40_DEBUG_FIFO_ERR          BIT(1)
--#define BCM2838_DMA40_DEBUG_READ_ERR          BIT(2)
--#define BCM2838_DMA40_DEBUG_READ_CB_ERR               BIT(3)
--#define BCM2838_DMA40_DEBUG_IN_ON_ERR         BIT(8)
--#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR      BIT(9)
--#define BCM2838_DMA40_DEBUG_HALT_ON_ERR               BIT(10)
--#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE  BIT(11)
--#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT      14
--#define BCM2838_DMA40_DEBUG_RSTATE_BITS               4
--#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT      18
--#define BCM2838_DMA40_DEBUG_WSTATE_BITS               4
--#define BCM2838_DMA40_DEBUG_RESET             BIT(23)
--#define BCM2838_DMA40_DEBUG_ID_SHIFT          24
--#define BCM2838_DMA40_DEBUG_ID_BITS           4
--#define BCM2838_DMA40_DEBUG_VERSION_SHIFT     28
--#define BCM2838_DMA40_DEBUG_VERSION_BITS      4
-+#define BCM2711_DMA40_DEBUG_WRITE_ERR         BIT(0)
-+#define BCM2711_DMA40_DEBUG_FIFO_ERR          BIT(1)
-+#define BCM2711_DMA40_DEBUG_READ_ERR          BIT(2)
-+#define BCM2711_DMA40_DEBUG_READ_CB_ERR               BIT(3)
-+#define BCM2711_DMA40_DEBUG_IN_ON_ERR         BIT(8)
-+#define BCM2711_DMA40_DEBUG_ABORT_ON_ERR      BIT(9)
-+#define BCM2711_DMA40_DEBUG_HALT_ON_ERR               BIT(10)
-+#define BCM2711_DMA40_DEBUG_DISABLE_CLK_GATE  BIT(11)
-+#define BCM2711_DMA40_DEBUG_RSTATE_SHIFT      14
-+#define BCM2711_DMA40_DEBUG_RSTATE_BITS               4
-+#define BCM2711_DMA40_DEBUG_WSTATE_SHIFT      18
-+#define BCM2711_DMA40_DEBUG_WSTATE_BITS               4
-+#define BCM2711_DMA40_DEBUG_RESET             BIT(23)
-+#define BCM2711_DMA40_DEBUG_ID_SHIFT          24
-+#define BCM2711_DMA40_DEBUG_ID_BITS           4
-+#define BCM2711_DMA40_DEBUG_VERSION_SHIFT     28
-+#define BCM2711_DMA40_DEBUG_VERSION_BITS      4
- /* Valid only for channels 0 - 3 (11 - 14) */
--#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
--#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
-+#define BCM2711_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
-+#define BCM2711_DMA40_CHANIO(base, n) ((base) + BCM2711_DMA_CHAN(n))
- /* the max dma length for different channels */
- #define MAX_DMA40_LEN SZ_1G
--#define BCM2838_DMA40_BURST_LEN(x)    ((min(x,16) - 1) << 8)
--#define BCM2838_DMA40_INC             BIT(12)
--#define BCM2838_DMA40_SIZE_32         (0 << 13)
--#define BCM2838_DMA40_SIZE_64         (1 << 13)
--#define BCM2838_DMA40_SIZE_128                (2 << 13)
--#define BCM2838_DMA40_SIZE_256                (3 << 13)
--#define BCM2838_DMA40_IGNORE          BIT(15)
--#define BCM2838_DMA40_STRIDE(x)               ((x) << 16) /* For 2D mode */
--
--#define BCM2838_DMA40_MEMCPY_FLAGS \
--      (BCM2838_DMA40_QOS(0) | \
--       BCM2838_DMA40_PANIC_QOS(0) | \
--       BCM2838_DMA40_WAIT_FOR_WRITES | \
--       BCM2838_DMA40_DISDEBUG)
--
--#define BCM2838_DMA40_MEMCPY_XFER_INFO \
--      (BCM2838_DMA40_SIZE_128 | \
--       BCM2838_DMA40_INC | \
--       BCM2838_DMA40_BURST_LEN(16))
-+#define BCM2711_DMA40_BURST_LEN(x)    ((min(x,16) - 1) << 8)
-+#define BCM2711_DMA40_INC             BIT(12)
-+#define BCM2711_DMA40_SIZE_32         (0 << 13)
-+#define BCM2711_DMA40_SIZE_64         (1 << 13)
-+#define BCM2711_DMA40_SIZE_128                (2 << 13)
-+#define BCM2711_DMA40_SIZE_256                (3 << 13)
-+#define BCM2711_DMA40_IGNORE          BIT(15)
-+#define BCM2711_DMA40_STRIDE(x)               ((x) << 16) /* For 2D mode */
-+
-+#define BCM2711_DMA40_MEMCPY_FLAGS \
-+      (BCM2711_DMA40_QOS(0) | \
-+       BCM2711_DMA40_PANIC_QOS(0) | \
-+       BCM2711_DMA40_WAIT_FOR_WRITES | \
-+       BCM2711_DMA40_DISDEBUG)
-+
-+#define BCM2711_DMA40_MEMCPY_XFER_INFO \
-+      (BCM2711_DMA40_SIZE_128 | \
-+       BCM2711_DMA40_INC | \
-+       BCM2711_DMA40_BURST_LEN(16))
- struct bcm2835_dmadev *memcpy_parent;
- static void __iomem *memcpy_chan;
--static struct bcm2838_dma40_scb *memcpy_scb;
-+static struct bcm2711_dma40_scb *memcpy_scb;
- static dma_addr_t memcpy_scb_dma;
- DEFINE_SPINLOCK(memcpy_lock);
-@@ -299,7 +299,7 @@ static const struct bcm2835_dma_cfg_data
-       .chan_40bit_mask = 0,
- };
--static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
-+static const struct bcm2835_dma_cfg_data bcm2711_dma_cfg = {
-       .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
- };
-@@ -332,27 +332,27 @@ static inline struct bcm2835_desc *to_bc
-       return container_of(t, struct bcm2835_desc, vd.tx);
- }
--static inline uint32_t to_bcm2838_ti(uint32_t info)
-+static inline uint32_t to_bcm2711_ti(uint32_t info)
- {
--      return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
--              ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
-+      return ((info & BCM2835_DMA_INT_EN) ? BCM2711_DMA40_INTEN : 0) |
-+              ((info & BCM2835_DMA_WAIT_RESP) ? BCM2711_DMA40_WAIT_RESP : 0) |
-               ((info & BCM2835_DMA_S_DREQ) ?
--               (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
--              ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
--              BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
-+               (BCM2711_DMA40_S_DREQ | BCM2711_DMA40_WAIT_RD_RESP) : 0) |
-+              ((info & BCM2835_DMA_D_DREQ) ? BCM2711_DMA40_D_DREQ : 0) |
-+              BCM2711_DMA40_PER_MAP((info >> 16) & 0x1f);
- }
--static inline uint32_t to_bcm2838_srci(uint32_t info)
-+static inline uint32_t to_bcm2711_srci(uint32_t info)
- {
--      return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
-+      return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0);
- }
--static inline uint32_t to_bcm2838_dsti(uint32_t info)
-+static inline uint32_t to_bcm2711_dsti(uint32_t info)
- {
--      return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
-+      return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0);
- }
--static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
-+static inline uint32_t to_bcm2711_cbaddr(dma_addr_t addr)
- {
-       BUG_ON(addr & 0x1f);
-       return (addr >> 5);
-@@ -412,12 +412,12 @@ static void bcm2835_dma_create_cb_set_le
-       }
-       if (c->is_40bit_channel) {
--              struct bcm2838_dma40_scb *scb =
--                      (struct bcm2838_dma40_scb *)control_block;
-+              struct bcm2711_dma40_scb *scb =
-+                      (struct bcm2711_dma40_scb *)control_block;
-               scb->len = cb_len;
-               /* add extrainfo bits to ti */
--              scb->ti |= to_bcm2838_ti(finalextrainfo);
-+              scb->ti |= to_bcm2711_ti(finalextrainfo);
-       } else {
-               control_block->length = cb_len;
-               /* add extrainfo bits to info */
-@@ -500,13 +500,13 @@ static struct bcm2835_desc *bcm2835_dma_
-               /* fill in the control block */
-               control_block = cb_entry->cb;
-               if (c->is_40bit_channel) {
--                      struct bcm2838_dma40_scb *scb =
--                              (struct bcm2838_dma40_scb *)control_block;
--                      scb->ti = to_bcm2838_ti(info);
-+                      struct bcm2711_dma40_scb *scb =
-+                              (struct bcm2711_dma40_scb *)control_block;
-+                      scb->ti = to_bcm2711_ti(info);
-                       scb->src = lower_32_bits(src);
--                      scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
-+                      scb->srci= upper_32_bits(src) | to_bcm2711_srci(info);
-                       scb->dst = lower_32_bits(dst);
--                      scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
-+                      scb->dsti = upper_32_bits(dst) | to_bcm2711_dsti(info);
-                       scb->next_cb = 0;
-               } else {
-                       control_block->info = info;
-@@ -531,7 +531,7 @@ static struct bcm2835_desc *bcm2835_dma_
-               /* link this the last controlblock */
-               if (frame && c->is_40bit_channel)
-                       d->cb_list[frame - 1].cb->next =
--                              to_bcm2838_cbaddr(cb_entry->paddr);
-+                              to_bcm2711_cbaddr(cb_entry->paddr);
-               if (frame && !c->is_40bit_channel)
-                       d->cb_list[frame - 1].cb->next = cb_entry->paddr;
-@@ -547,10 +547,10 @@ static struct bcm2835_desc *bcm2835_dma_
-       /* the last frame requires extra flags */
-       if (c->is_40bit_channel) {
--              struct bcm2838_dma40_scb *scb =
--                      (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
-+              struct bcm2711_dma40_scb *scb =
-+                      (struct bcm2711_dma40_scb *)d->cb_list[d->frames-1].cb;
--              scb->ti |= to_bcm2838_ti(finalextrainfo);
-+              scb->ti |= to_bcm2711_ti(finalextrainfo);
-       } else {
-               d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-       }
-@@ -581,18 +581,18 @@ static void bcm2835_dma_fill_cb_chain_wi
-       max_len = bcm2835_dma_max_frame_length(c);
-       for_each_sg(sgl, sgent, sg_len, i) {
-               if (c->is_40bit_channel) {
--                      struct bcm2838_dma40_scb *scb =
--                              (struct bcm2838_dma40_scb *)cb->cb;
-+                      struct bcm2711_dma40_scb *scb =
-+                              (struct bcm2711_dma40_scb *)cb->cb;
-                       for (addr = sg_dma_address(sgent),
-                                    len = sg_dma_len(sgent);
-                            len > 0;
-                            addr += scb->len, len -= scb->len, scb++) {
-                               if (direction == DMA_DEV_TO_MEM) {
-                                       scb->dst = lower_32_bits(addr);
--                                      scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+                                      scb->dsti = upper_32_bits(addr) | BCM2711_DMA40_INC;
-                               } else {
-                                       scb->src = lower_32_bits(addr);
--                                      scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+                                      scb->srci = upper_32_bits(addr) | BCM2711_DMA40_INC;
-                               }
-                               scb->len = min(len, max_len);
-                       }
-@@ -619,7 +619,7 @@ static void bcm2835_dma_abort(struct bcm
-       u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
-       if (c->is_40bit_channel)
--              wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
-+              wait_mask = BCM2711_DMA40_WAITING_FOR_WRITES;
-       /*
-        * A zero control block address means the channel is idle.
-@@ -658,10 +658,10 @@ static void bcm2835_dma_start_desc(struc
-       c->desc = d = to_bcm2835_dma_desc(&vd->tx);
-       if (c->is_40bit_channel) {
--              writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
--                     c->chan_base + BCM2838_DMA40_CB);
--              writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
--                     c->chan_base + BCM2838_DMA40_CS);
-+              writel(to_bcm2711_cbaddr(d->cb_list[0].paddr),
-+                     c->chan_base + BCM2711_DMA40_CB);
-+              writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_CS_FLAGS(c->dreq),
-+                     c->chan_base + BCM2711_DMA40_CS);
-       } else {
-               writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-               writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-@@ -694,7 +694,7 @@ static irqreturn_t bcm2835_dma_callback(
-        * will remain idle despite the ACTIVE flag being set.
-        */
-       writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
--             (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
-+             (c->is_40bit_channel ? BCM2711_DMA40_CS_FLAGS(c->dreq) :
-               BCM2835_DMA_CS_FLAGS(c->dreq)),
-              c->chan_base + BCM2835_DMA_CS);
-@@ -799,14 +799,14 @@ static enum dma_status bcm2835_dma_tx_st
-               dma_addr_t pos;
-               if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
--                      pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
--                              ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
-+                      pos = readl(c->chan_base + BCM2711_DMA40_SRC) +
-+                              ((readl(c->chan_base + BCM2711_DMA40_SRCI) &
-                                 0xff) << 8);
-               else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
-                       pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
-               else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
--                      pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
--                              ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
-+                      pos = readl(c->chan_base + BCM2711_DMA40_DEST) +
-+                              ((readl(c->chan_base + BCM2711_DMA40_DESTI) &
-                                 0xff) << 8);
-               else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
-                       pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
-@@ -1007,7 +1007,7 @@ static struct dma_async_tx_descriptor *b
-       /* wrap around into a loop */
-       d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
--              to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-+              to_bcm2711_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-       return vchan_tx_prep(&c->vc, &d->vd, flags);
- }
-@@ -1095,7 +1095,7 @@ static void bcm2835_dma_free(struct bcm2
-                            DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
--int bcm2838_dma40_memcpy_init(void)
-+int bcm2711_dma40_memcpy_init(void)
- {
-       if (!memcpy_parent)
-               return -EPROBE_DEFER;
-@@ -1108,15 +1108,15 @@ int bcm2838_dma40_memcpy_init(void)
-       return 0;
- }
--EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
-+EXPORT_SYMBOL(bcm2711_dma40_memcpy_init);
--void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
-+void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
- {
--      struct bcm2838_dma40_scb *scb = memcpy_scb;
-+      struct bcm2711_dma40_scb *scb = memcpy_scb;
-       unsigned long flags;
-       if (!scb) {
--              pr_err("bcm2838_dma40_memcpy not initialised!\n");
-+              pr_err("bcm2711_dma40_memcpy not initialised!\n");
-               return;
-       }
-@@ -1124,29 +1124,29 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
-       scb->ti = 0;
-       scb->src = lower_32_bits(src);
--      scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+      scb->srci = upper_32_bits(src) | BCM2711_DMA40_MEMCPY_XFER_INFO;
-       scb->dst = lower_32_bits(dst);
--      scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+      scb->dsti = upper_32_bits(dst) | BCM2711_DMA40_MEMCPY_XFER_INFO;
-       scb->len = size;
-       scb->next_cb = 0;
--      writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
--      writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
--             memcpy_chan + BCM2838_DMA40_CS);
-+      writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2711_DMA40_CB);
-+      writel(BCM2711_DMA40_MEMCPY_FLAGS + BCM2711_DMA40_ACTIVE,
-+             memcpy_chan + BCM2711_DMA40_CS);
-       /* Poll for completion */
--      while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
-+      while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END))
-               cpu_relax();
--      writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
-+      writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS);
-       spin_unlock_irqrestore(&memcpy_lock, flags);
- }
--EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-+EXPORT_SYMBOL(bcm2711_dma40_memcpy);
- static const struct of_device_id bcm2835_dma_of_match[] = {
-       { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
--      { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
-+      { .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg },
-       {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-@@ -1274,9 +1274,9 @@ static int bcm2835_dma_probe(struct plat
-       /* And possibly one for the 40-bit DMA memcpy API */
-       if (chans_available & od->cfg_data->chan_40bit_mask &
--          BIT(BCM2838_DMA_MEMCPY_CHAN)) {
-+          BIT(BCM2711_DMA_MEMCPY_CHAN)) {
-               memcpy_parent = od;
--              memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
-+              memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2711_DMA_MEMCPY_CHAN);
-               memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
-                                               sizeof(*memcpy_scb),
-                                               &memcpy_scb_dma, GFP_KERNEL);
-@@ -1284,7 +1284,7 @@ static int bcm2835_dma_probe(struct plat
-                       dev_warn(&pdev->dev,
-                                "Failed to allocated memcpy scb\n");
--              chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
-+              chans_available &= ~BIT(BCM2711_DMA_MEMCPY_CHAN);
-       }
-       /* get irqs for each channel that we support */
diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch
new file mode 100644 (file)
index 0000000..1056cfc
--- /dev/null
@@ -0,0 +1,39 @@
+From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 18:23:01 +0100
+Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper
+
+commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream.
+
+Add of_get_next_dma_parent() helper which is similar to
+__of_get_dma_parent(), but can be used in iterators and decrements the
+ref count on the prior parent.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_
+       return of_node_get(args.np);
+ }
++static struct device_node *of_get_next_dma_parent(struct device_node *np)
++{
++      struct device_node *parent;
++
++      parent = __of_get_dma_parent(np);
++      of_node_put(np);
++
++      return parent;
++}
++
+ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
+ {
+       struct device_node *host;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch
new file mode 100644 (file)
index 0000000..dbfb102
--- /dev/null
@@ -0,0 +1,30 @@
+From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 14:47:31 +0100
+Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent"
+
+commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream.
+
+Much like for address translation, when checking for DMA coherence we
+should be sure to walk up the DMA hierarchy, rather than the MMIO one,
+now that we can accommodate them being different.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -1023,7 +1023,7 @@ bool of_dma_is_coherent(struct device_no
+                       of_node_put(node);
+                       return true;
+               }
+-              node = of_get_next_parent(node);
++              node = of_get_next_dma_parent(node);
+       }
+       of_node_put(node);
+       return false;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch
new file mode 100644 (file)
index 0000000..045ee98
--- /dev/null
@@ -0,0 +1,117 @@
+From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Tue, 2 Jul 2019 18:42:39 +0100
+Subject: [PATCH] of: Factor out #{addr,size}-cells parsing
+
+In some cases such as PCI host controllers, we may have a "parent bus"
+which is an OF leaf node, but still need to correctly parse ranges from
+the point of view of that bus. For that, factor out variants of the
+"#addr-cells" and "#size-cells" parsers which do not assume they have a
+device node and thus immediately traverse upwards before reading the
+relevant property.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+[robh: don't make of_bus_n_{addr,size}_cells() public]
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+
+(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a)
+---
+ drivers/of/address.c    |  2 ++
+ drivers/of/base.c       | 32 ++++++++++++++++++++++----------
+ drivers/of/of_private.h | 14 ++++++++++++++
+ 3 files changed, 38 insertions(+), 10 deletions(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -14,6 +14,8 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
++#include "of_private.h"
++
+ /* Max address size we deal with */
+ #define OF_MAX_ADDR_CELLS     4
+ #define OF_CHECK_ADDR_COUNT(na)       ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru
+       return np && match && type && !strcmp(match, type);
+ }
+-int of_n_addr_cells(struct device_node *np)
++int of_bus_n_addr_cells(struct device_node *np)
+ {
+       u32 cells;
+-      do {
+-              if (np->parent)
+-                      np = np->parent;
++      for (; np; np = np->parent)
+               if (!of_property_read_u32(np, "#address-cells", &cells))
+                       return cells;
+-      } while (np->parent);
++
+       /* No #address-cells property for the root node */
+       return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+ }
++
++int of_n_addr_cells(struct device_node *np)
++{
++      if (np->parent)
++              np = np->parent;
++
++      return of_bus_n_addr_cells(np);
++}
+ EXPORT_SYMBOL(of_n_addr_cells);
+-int of_n_size_cells(struct device_node *np)
++int of_bus_n_size_cells(struct device_node *np)
+ {
+       u32 cells;
+-      do {
+-              if (np->parent)
+-                      np = np->parent;
++      for (; np; np = np->parent)
+               if (!of_property_read_u32(np, "#size-cells", &cells))
+                       return cells;
+-      } while (np->parent);
++
+       /* No #size-cells property for the root node */
+       return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+ }
++
++int of_n_size_cells(struct device_node *np)
++{
++      if (np->parent)
++              np = np->parent;
++
++      return of_bus_n_size_cells(np);
++}
+ EXPORT_SYMBOL(of_n_size_cells);
+ #ifdef CONFIG_NUMA
+--- a/drivers/of/of_private.h
++++ b/drivers/of/of_private.h
+@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s
+ #define for_each_transaction_entry_reverse(_oft, _te) \
+       list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
++extern int of_bus_n_addr_cells(struct device_node *np);
++extern int of_bus_n_size_cells(struct device_node *np);
++
++#ifdef CONFIG_OF_ADDRESS
++extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
++                          u64 *paddr, u64 *size);
++#else
++static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
++                                 u64 *paddr, u64 *size)
++{
++      return -ENODEV;
++}
++#endif
++
+ #endif /* _LINUX_OF_PRIVATE_H */
diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch
new file mode 100644 (file)
index 0000000..28d1987
--- /dev/null
@@ -0,0 +1,40 @@
+From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 4 Sep 2019 11:43:30 +0100
+Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes
+ missing 'dma-ranges'
+
+commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream.
+
+'dma-ranges' frequently exists without parent nodes having 'dma-ranges'.
+While this is an error for 'ranges', this is fine because DMA capable
+devices always have a translatable DMA address. Also, with no
+'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with
+no restrictions unless perhaps the device itself has implicit
+restrictions.
+
+Cc: Robin Murphy <robin.murphy@arm.com>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -519,9 +519,13 @@ static int of_translate_one(struct devic
+        *
+        * As far as we know, this damage only exists on Apple machines, so
+        * This code is only enabled on powerpc. --gcl
++       *
++       * This quirk also applies for 'dma-ranges' which frequently exist in
++       * child nodes without 'dma-ranges' in the parent nodes. --RobH
+        */
+       ranges = of_get_property(parent, rprop, &rlen);
+-      if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
++      if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
++          strcmp(rprop, "dma-ranges")) {
+               pr_debug("no ranges; cannot translate\n");
+               return 1;
+       }
diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-pcie-brcmstb-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0444-pcie-brcmstb-Correct-SoC-name.patch
deleted file mode 100644 (file)
index 3bbcdd5..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-From 900b4ad0814df7dbacb01318bf49af5bab605fa0 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:39:40 +0000
-Subject: [PATCH] pcie-brcmstb: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "bcm2835-dma: Add proper 40-bit DMA support"
-Fixes: "Ported pcie-brcmstb bounce buffer implementation to ARM64."
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/pci/controller/pcie-brcmstb-bounce.c   | 10 +++++-----
- drivers/pci/controller/pcie-brcmstb-bounce64.c | 10 +++++-----
- 2 files changed, 10 insertions(+), 10 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -91,8 +91,8 @@ struct dmabounce_device_info {
- static struct dmabounce_device_info *g_dmabounce_device_info;
--extern int bcm2838_dma40_memcpy_init(void);
--extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+extern int bcm2711_dma40_memcpy_init(void);
-+extern void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
- #ifdef STATS
- static ssize_t
-@@ -320,7 +320,7 @@ map_single(struct device *dev, struct sa
-       if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-           !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
--              bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+              bcm2711_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-                                    size);
-       return buf->safe_dma_addr;
-@@ -338,7 +338,7 @@ unmap_single(struct device *dev, struct
-               dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-                       (u64)buf->unsafe_dma_addr);
--              bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+              bcm2711_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-                                    size);
-       }
-       return buf->unsafe_dma_addr;
-@@ -476,7 +476,7 @@ int brcm_pcie_bounce_init(struct device
-       if (g_dmabounce_device_info)
-               return -EBUSY;
--      ret = bcm2838_dma40_memcpy_init();
-+      ret = bcm2711_dma40_memcpy_init();
-       if (ret)
-               return ret;
---- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -93,8 +93,8 @@ struct dmabounce_device_info {
- static struct dmabounce_device_info *g_dmabounce_device_info;
--extern int bcm2838_dma40_memcpy_init(void);
--extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+extern int bcm2711_dma40_memcpy_init(void);
-+extern void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
- #ifdef STATS
- static ssize_t
-@@ -322,7 +322,7 @@ map_single(struct device *dev, struct sa
-       if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-           !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
--              bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+              bcm2711_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-                                    size);
-       return buf->safe_dma_addr;
-@@ -340,7 +340,7 @@ unmap_single(struct device *dev, struct
-               dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-                       (u64)buf->unsafe_dma_addr);
--              bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+              bcm2711_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-                                    size);
-       }
-       return buf->unsafe_dma_addr;
-@@ -483,7 +483,7 @@ int brcm_pcie_bounce_init(struct device
-       if (g_dmabounce_device_info)
-               return -EBUSY;
--      ret = bcm2838_dma40_memcpy_init();
-+      ret = bcm2711_dma40_memcpy_init();
-       if (ret)
-               return ret;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch
new file mode 100644 (file)
index 0000000..1cac2df
--- /dev/null
@@ -0,0 +1,107 @@
+From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 18:42:20 +0100
+Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes
+
+commit 951d48855d86e72e0d6de73440fe09d363168064 upstream.
+
+Since the "dma-ranges" property is only valid for a node representing a
+bus, of_dma_get_range() currently assumes the node passed in is a leaf
+representing a device, and starts the walk from its parent. In cases
+like PCI host controllers on typical FDT systems, however, where the PCI
+endpoints are probed dynamically the initial leaf node represents the
+'bus' itself, and this logic means we fail to consider any "dma-ranges"
+describing the host bridge itself. Rework the logic such that
+of_dma_get_range() also works correctly starting from a bus node
+containing "dma-ranges".
+
+While this does mean "dma-ranges" could incorrectly be in a device leaf
+node, there isn't really any way in this function to ensure that a leaf
+node is or isn't a bus node.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+[robh: Allow for the bus child node to still be passed in]
+Signed-off-by: Rob Herring <robh@kernel.org>
+Reviewed-by: Robin Murphy <robin.murphy@arm.com>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+---
+ drivers/of/address.c | 44 ++++++++++++++++++--------------------------
+ 1 file changed, 18 insertions(+), 26 deletions(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node
+       const __be32 *ranges = NULL;
+       int len, naddr, nsize, pna;
+       int ret = 0;
++      bool found_dma_ranges = false;
+       u64 dmaaddr;
+-      if (!node)
+-              return -EINVAL;
+-
+-      while (1) {
+-              struct device_node *parent;
+-
+-              naddr = of_n_addr_cells(node);
+-              nsize = of_n_size_cells(node);
+-
+-              parent = __of_get_dma_parent(node);
+-              of_node_put(node);
+-
+-              node = parent;
+-              if (!node)
+-                      break;
+-
++      while (node) {
+               ranges = of_get_property(node, "dma-ranges", &len);
+               /* Ignore empty ranges, they imply no translation required */
+               if (ranges && len > 0)
+                       break;
+-              /*
+-               * At least empty ranges has to be defined for parent node if
+-               * DMA is supported
+-               */
+-              if (!ranges)
+-                      break;
++              /* Once we find 'dma-ranges', then a missing one is an error */
++              if (found_dma_ranges && !ranges) {
++                      ret = -ENODEV;
++                      goto out;
++              }
++              found_dma_ranges = true;
++
++              node = of_get_next_dma_parent(node);
+       }
+-      if (!ranges) {
++      if (!node || !ranges) {
+               pr_debug("no dma-ranges found for node(%pOF)\n", np);
+               ret = -ENODEV;
+               goto out;
+       }
+-      len /= sizeof(u32);
+-
++      naddr = of_bus_n_addr_cells(node);
++      nsize = of_bus_n_size_cells(node);
+       pna = of_n_addr_cells(node);
++      if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
++              ret = -EINVAL;
++              goto out;
++      }
+       /* dma-ranges format:
+        * DMA addr     : naddr cells
+@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node
+        * size         : nsize cells
+        */
+       dmaaddr = of_read_number(ranges, naddr);
+-      *paddr = of_translate_dma_address(np, ranges);
++      *paddr = of_translate_dma_address(node, ranges + naddr);
+       if (*paddr == OF_BAD_ADDR) {
+               pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
+                      dma_addr, np);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch
new file mode 100644 (file)
index 0000000..a90e7f8
--- /dev/null
@@ -0,0 +1,30 @@
+From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:43 +0200
+Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of
+ calling max_zone_dma_phys()
+
+commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream.
+
+By the time we call zones_sizes_init() arm64_dma_phys_limit already
+contains the result of max_zone_dma_phys(). We use the variable instead
+of calling the function directly to save some precious cpu time.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/mm/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig
+       unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
+ #ifdef CONFIG_ZONE_DMA32
+-      max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys());
++      max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
+ #endif
+       max_zone_pfns[ZONE_NORMAL] = max;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch
new file mode 100644 (file)
index 0000000..3039bfe
--- /dev/null
@@ -0,0 +1,117 @@
+From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:44 +0200
+Subject: [PATCH] arm64: rename variables used to calculate
+ ZONE_DMA32's size
+
+commit a573cdd7973dedd87e62196c400332896bb236c8 upstream.
+
+Let the name indicate that they are used to calculate ZONE_DMA32's size
+as opposed to ZONE_DMA.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/mm/init.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -56,7 +56,7 @@ EXPORT_SYMBOL(physvirt_offset);
+ struct page *vmemmap __ro_after_init;
+ EXPORT_SYMBOL(vmemmap);
+-phys_addr_t arm64_dma_phys_limit __ro_after_init;
++phys_addr_t arm64_dma32_phys_limit __ro_after_init;
+ #ifdef CONFIG_KEXEC_CORE
+ /*
+@@ -174,7 +174,7 @@ static void __init reserve_elfcorehdr(vo
+  * currently assumes that for memory starting above 4G, 32-bit devices will
+  * use a DMA offset.
+  */
+-static phys_addr_t __init max_zone_dma_phys(void)
++static phys_addr_t __init max_zone_dma32_phys(void)
+ {
+       phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+       return min(offset + (1ULL << 32), memblock_end_of_DRAM());
+@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig
+       unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
+ #ifdef CONFIG_ZONE_DMA32
+-      max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
++      max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
+ #endif
+       max_zone_pfns[ZONE_NORMAL] = max;
+@@ -200,16 +200,16 @@ static void __init zone_sizes_init(unsig
+ {
+       struct memblock_region *reg;
+       unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
+-      unsigned long max_dma = min;
++      unsigned long max_dma32 = min;
+       memset(zone_size, 0, sizeof(zone_size));
+       /* 4GB maximum for 32-bit only capable devices */
+ #ifdef CONFIG_ZONE_DMA32
+-      max_dma = PFN_DOWN(arm64_dma_phys_limit);
+-      zone_size[ZONE_DMA32] = max_dma - min;
++      max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
++      zone_size[ZONE_DMA32] = max_dma32 - min;
+ #endif
+-      zone_size[ZONE_NORMAL] = max - max_dma;
++      zone_size[ZONE_NORMAL] = max - max_dma32;
+       memcpy(zhole_size, zone_size, sizeof(zhole_size));
+@@ -221,14 +221,14 @@ static void __init zone_sizes_init(unsig
+                       continue;
+ #ifdef CONFIG_ZONE_DMA32
+-              if (start < max_dma) {
+-                      unsigned long dma_end = min(end, max_dma);
++              if (start < max_dma32) {
++                      unsigned long dma_end = min(end, max_dma32);
+                       zhole_size[ZONE_DMA32] -= dma_end - start;
+               }
+ #endif
+-              if (end > max_dma) {
++              if (end > max_dma32) {
+                       unsigned long normal_end = min(end, max);
+-                      unsigned long normal_start = max(start, max_dma);
++                      unsigned long normal_start = max(start, max_dma32);
+                       zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
+               }
+       }
+@@ -420,9 +420,9 @@ void __init arm64_memblock_init(void)
+       /* 4GB maximum for 32-bit only capable devices */
+       if (IS_ENABLED(CONFIG_ZONE_DMA32))
+-              arm64_dma_phys_limit = max_zone_dma_phys();
++              arm64_dma32_phys_limit = max_zone_dma32_phys();
+       else
+-              arm64_dma_phys_limit = PHYS_MASK + 1;
++              arm64_dma32_phys_limit = PHYS_MASK + 1;
+       reserve_crashkernel();
+@@ -430,7 +430,7 @@ void __init arm64_memblock_init(void)
+       high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+-      dma_contiguous_reserve(arm64_dma_phys_limit);
++      dma_contiguous_reserve(arm64_dma32_phys_limit);
+ }
+ void __init bootmem_init(void)
+@@ -534,7 +534,7 @@ static void __init free_unused_memmap(vo
+ void __init mem_init(void)
+ {
+       if (swiotlb_force == SWIOTLB_FORCE ||
+-          max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT))
++          max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
+               swiotlb_init(1);
+       else
+               swiotlb_force = SWIOTLB_NO_FORCE;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch
new file mode 100644 (file)
index 0000000..2397c71
--- /dev/null
@@ -0,0 +1,174 @@
+From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:45 +0200
+Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32
+
+commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream.
+
+So far all arm64 devices have supported 32 bit DMA masks for their
+peripherals. This is not true anymore for the Raspberry Pi 4 as most of
+it's peripherals can only address the first GB of memory on a total of
+up to 4 GB.
+
+This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32
+to be addressable with a 32 bit mask. So it was decided to re-introduce
+ZONE_DMA in arm64.
+
+ZONE_DMA will contain the lower 1G of memory, which is currently the
+memory area addressable by any peripheral on an arm64 device.
+ZONE_DMA32 will contain the rest of the 32 bit addressable memory.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/Kconfig            |  4 +++
+ arch/arm64/include/asm/page.h |  2 ++
+ arch/arm64/mm/init.c          | 54 +++++++++++++++++++++++++----------
+ 3 files changed, 45 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -267,6 +267,10 @@ config GENERIC_CSUM
+ config GENERIC_CALIBRATE_DELAY
+       def_bool y
++config ZONE_DMA
++      bool "Support DMA zone" if EXPERT
++      default y
++
+ config ZONE_DMA32
+       bool "Support DMA32 zone" if EXPERT
+       default y
+--- a/arch/arm64/include/asm/page.h
++++ b/arch/arm64/include/asm/page.h
+@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long);
+ #include <asm-generic/getorder.h>
++#define ARCH_ZONE_DMA_BITS 30
++
+ #endif
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -56,6 +56,13 @@ EXPORT_SYMBOL(physvirt_offset);
+ struct page *vmemmap __ro_after_init;
+ EXPORT_SYMBOL(vmemmap);
++/*
++ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of
++ * memory as some devices, namely the Raspberry Pi 4, have peripherals with
++ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32
++ * bit addressable memory area.
++ */
++phys_addr_t arm64_dma_phys_limit __ro_after_init;
+ phys_addr_t arm64_dma32_phys_limit __ro_after_init;
+ #ifdef CONFIG_KEXEC_CORE
+@@ -169,15 +176,16 @@ static void __init reserve_elfcorehdr(vo
+ {
+ }
+ #endif /* CONFIG_CRASH_DUMP */
++
+ /*
+- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It
+- * currently assumes that for memory starting above 4G, 32-bit devices will
+- * use a DMA offset.
++ * Return the maximum physical address for a zone with a given address size
++ * limit. It currently assumes that for memory starting above 4G, 32-bit
++ * devices will use a DMA offset.
+  */
+-static phys_addr_t __init max_zone_dma32_phys(void)
++static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
+ {
+-      phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+-      return min(offset + (1ULL << 32), memblock_end_of_DRAM());
++      phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits);
++      return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM());
+ }
+ #ifdef CONFIG_NUMA
+@@ -186,6 +194,9 @@ static void __init zone_sizes_init(unsig
+ {
+       unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
++#ifdef CONFIG_ZONE_DMA
++      max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
++#endif
+ #ifdef CONFIG_ZONE_DMA32
+       max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
+ #endif
+@@ -201,13 +212,18 @@ static void __init zone_sizes_init(unsig
+       struct memblock_region *reg;
+       unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
+       unsigned long max_dma32 = min;
++      unsigned long max_dma = min;
+       memset(zone_size, 0, sizeof(zone_size));
+-      /* 4GB maximum for 32-bit only capable devices */
++#ifdef CONFIG_ZONE_DMA
++      max_dma = PFN_DOWN(arm64_dma_phys_limit);
++      zone_size[ZONE_DMA] = max_dma - min;
++      max_dma32 = max_dma;
++#endif
+ #ifdef CONFIG_ZONE_DMA32
+       max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
+-      zone_size[ZONE_DMA32] = max_dma32 - min;
++      zone_size[ZONE_DMA32] = max_dma32 - max_dma;
+ #endif
+       zone_size[ZONE_NORMAL] = max - max_dma32;
+@@ -219,11 +235,17 @@ static void __init zone_sizes_init(unsig
+               if (start >= max)
+                       continue;
+-
++#ifdef CONFIG_ZONE_DMA
++              if (start < max_dma) {
++                      unsigned long dma_end = min_not_zero(end, max_dma);
++                      zhole_size[ZONE_DMA] -= dma_end - start;
++              }
++#endif
+ #ifdef CONFIG_ZONE_DMA32
+               if (start < max_dma32) {
+-                      unsigned long dma_end = min(end, max_dma32);
+-                      zhole_size[ZONE_DMA32] -= dma_end - start;
++                      unsigned long dma32_end = min(end, max_dma32);
++                      unsigned long dma32_start = max(start, max_dma);
++                      zhole_size[ZONE_DMA32] -= dma32_end - dma32_start;
+               }
+ #endif
+               if (end > max_dma32) {
+@@ -418,9 +440,11 @@ void __init arm64_memblock_init(void)
+       early_init_fdt_scan_reserved_mem();
+-      /* 4GB maximum for 32-bit only capable devices */
++      if (IS_ENABLED(CONFIG_ZONE_DMA))
++              arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS);
++
+       if (IS_ENABLED(CONFIG_ZONE_DMA32))
+-              arm64_dma32_phys_limit = max_zone_dma32_phys();
++              arm64_dma32_phys_limit = max_zone_phys(32);
+       else
+               arm64_dma32_phys_limit = PHYS_MASK + 1;
+@@ -430,7 +454,7 @@ void __init arm64_memblock_init(void)
+       high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+-      dma_contiguous_reserve(arm64_dma32_phys_limit);
++      dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit);
+ }
+ void __init bootmem_init(void)
+@@ -534,7 +558,7 @@ static void __init free_unused_memmap(vo
+ void __init mem_init(void)
+ {
+       if (swiotlb_force == SWIOTLB_FORCE ||
+-          max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
++          max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit))
+               swiotlb_init(1);
+       else
+               swiotlb_force = SWIOTLB_NO_FORCE;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch
new file mode 100644 (file)
index 0000000..23811e0
--- /dev/null
@@ -0,0 +1,84 @@
+From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:46 +0200
+Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum
+ zone_type'
+
+commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream.
+
+These zones usage has evolved with time and the comments were outdated.
+This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date
+examples on how they are used on different architectures.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------
+ 1 file changed, 26 insertions(+), 19 deletions(-)
+
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -358,33 +358,40 @@ struct per_cpu_nodestat {
+ #endif /* !__GENERATING_BOUNDS.H */
+ enum zone_type {
+-#ifdef CONFIG_ZONE_DMA
+       /*
+-       * ZONE_DMA is used when there are devices that are not able
+-       * to do DMA to all of addressable memory (ZONE_NORMAL). Then we
+-       * carve out the portion of memory that is needed for these devices.
+-       * The range is arch specific.
+-       *
+-       * Some examples
+-       *
+-       * Architecture         Limit
+-       * ---------------------------
+-       * parisc, ia64, sparc  <4G
+-       * s390, powerpc        <2G
+-       * arm                  Various
+-       * alpha                Unlimited or 0-16MB.
++       * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able
++       * to DMA to all of the addressable memory (ZONE_NORMAL).
++       * On architectures where this area covers the whole 32 bit address
++       * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller
++       * DMA addressing constraints. This distinction is important as a 32bit
++       * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit
++       * platforms may need both zones as they support peripherals with
++       * different DMA addressing limitations.
++       *
++       * Some examples:
++       *
++       *  - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the
++       *    rest of the lower 4G.
++       *
++       *  - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on
++       *    the specific device.
++       *
++       *  - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the
++       *    lower 4G.
++       *
++       *  - powerpc only uses ZONE_DMA, the size, up to 2G, may vary
++       *    depending on the specific device.
+        *
+-       * i386, x86_64 and multiple other arches
+-       *                      <16M.
++       *  - s390 uses ZONE_DMA fixed to the lower 2G.
++       *
++       *  - ia64 and riscv only use ZONE_DMA32.
++       *
++       *  - parisc uses neither.
+        */
++#ifdef CONFIG_ZONE_DMA
+       ZONE_DMA,
+ #endif
+ #ifdef CONFIG_ZONE_DMA32
+-      /*
+-       * x86_64 needs two ZONE_DMAs because it supports devices that are
+-       * only able to do DMA to the lower 16M but also 32 bit devices that
+-       * can only do DMA areas below 4G.
+-       */
+       ZONE_DMA32,
+ #endif
+       /*
diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch
new file mode 100644 (file)
index 0000000..c2c959a
--- /dev/null
@@ -0,0 +1,36 @@
+From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Mon, 28 Oct 2019 11:32:32 -0500
+Subject: [PATCH] resource: Add a resource_list_first_type helper
+
+commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream.
+
+A common pattern is looping over a resource_list just to get a matching
+entry with a specific type. Add resource_list_first_type() helper which
+implements this.
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ include/linux/resource_ext.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/linux/resource_ext.h
++++ b/include/linux/resource_ext.h
+@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou
+ #define resource_list_for_each_entry_safe(entry, tmp, list)   \
+       list_for_each_entry_safe((entry), (tmp), (list), node)
++static inline struct resource_entry *
++resource_list_first_type(struct list_head *list, unsigned long type)
++{
++      struct resource_entry *entry;
++
++      resource_list_for_each_entry(entry, list) {
++              if (resource_type(entry->res) == type)
++                      return entry;
++      }
++      return NULL;
++}
++
+ #endif /* _LINUX_RESOURCE_EXT_H */
diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch
new file mode 100644 (file)
index 0000000..5de73d3
--- /dev/null
@@ -0,0 +1,195 @@
+From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Mon, 14 Oct 2019 20:31:03 +0200
+Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable
+
+commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream.
+
+Some architectures, notably ARM, are interested in tweaking this
+depending on their runtime DMA addressing limitations.
+
+Acked-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/include/asm/page.h   |  2 --
+ arch/arm64/mm/init.c            |  9 +++++++--
+ arch/powerpc/include/asm/page.h |  9 ---------
+ arch/powerpc/mm/mem.c           | 20 +++++++++++++++-----
+ arch/s390/include/asm/page.h    |  2 --
+ arch/s390/mm/init.c             |  1 +
+ include/linux/dma-direct.h      |  2 ++
+ kernel/dma/direct.c             | 13 ++++++-------
+ 8 files changed, 31 insertions(+), 27 deletions(-)
+
+--- a/arch/arm64/include/asm/page.h
++++ b/arch/arm64/include/asm/page.h
+@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long);
+ #include <asm-generic/getorder.h>
+-#define ARCH_ZONE_DMA_BITS 30
+-
+ #endif
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -20,6 +20,7 @@
+ #include <linux/sort.h>
+ #include <linux/of.h>
+ #include <linux/of_fdt.h>
++#include <linux/dma-direct.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dma-contiguous.h>
+ #include <linux/efi.h>
+@@ -41,6 +42,8 @@
+ #include <asm/tlb.h>
+ #include <asm/alternative.h>
++#define ARM64_ZONE_DMA_BITS   30
++
+ /*
+  * We need to be able to catch inadvertent references to memstart_addr
+  * that occur (potentially in generic code) before arm64_memblock_init()
+@@ -440,8 +443,10 @@ void __init arm64_memblock_init(void)
+       early_init_fdt_scan_reserved_mem();
+-      if (IS_ENABLED(CONFIG_ZONE_DMA))
+-              arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS);
++      if (IS_ENABLED(CONFIG_ZONE_DMA)) {
++              zone_dma_bits = ARM64_ZONE_DMA_BITS;
++              arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS);
++      }
+       if (IS_ENABLED(CONFIG_ZONE_DMA32))
+               arm64_dma32_phys_limit = max_zone_phys(32);
+--- a/arch/powerpc/include/asm/page.h
++++ b/arch/powerpc/include/asm/page.h
+@@ -334,13 +334,4 @@ struct vm_area_struct;
+ #endif /* __ASSEMBLY__ */
+ #include <asm/slice.h>
+-/*
+- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks.
+- */
+-#ifdef CONFIG_PPC32
+-#define ARCH_ZONE_DMA_BITS 30
+-#else
+-#define ARCH_ZONE_DMA_BITS 31
+-#endif
+-
+ #endif /* _ASM_POWERPC_PAGE_H */
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -31,6 +31,7 @@
+ #include <linux/slab.h>
+ #include <linux/vmalloc.h>
+ #include <linux/memremap.h>
++#include <linux/dma-direct.h>
+ #include <asm/pgalloc.h>
+ #include <asm/prom.h>
+@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi
+  * everything else. GFP_DMA32 page allocations automatically fall back to
+  * ZONE_DMA.
+  *
+- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to
+- * inform the generic DMA mapping code.  32-bit only devices (if not handled
+- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get
+- * otherwise served by ZONE_DMA.
++ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the
++ * generic DMA mapping code.  32-bit only devices (if not handled by an IOMMU
++ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by
++ * ZONE_DMA.
+  */
+ static unsigned long max_zone_pfns[MAX_NR_ZONES];
+@@ -259,9 +260,18 @@ void __init paging_init(void)
+       printk(KERN_DEBUG "Memory hole size: %ldMB\n",
+              (long int)((top_of_ram - total_ram) >> 20));
++      /*
++       * Allow 30-bit DMA for very limited Broadcom wifi chips on many
++       * powerbooks.
++       */
++      if (IS_ENABLED(CONFIG_PPC32))
++              zone_dma_bits = 30;
++      else
++              zone_dma_bits = 31;
++
+ #ifdef CONFIG_ZONE_DMA
+       max_zone_pfns[ZONE_DMA] = min(max_low_pfn,
+-                                    1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT));
++                                    1UL << (zone_dma_bits - PAGE_SHIFT));
+ #endif
+       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ #ifdef CONFIG_HIGHMEM
+--- a/arch/s390/include/asm/page.h
++++ b/arch/s390/include/asm/page.h
+@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+-#define ARCH_ZONE_DMA_BITS    31
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/getorder.h>
+--- a/arch/s390/mm/init.c
++++ b/arch/s390/mm/init.c
+@@ -118,6 +118,7 @@ void __init paging_init(void)
+       sparse_memory_present_with_active_regions(MAX_NUMNODES);
+       sparse_init();
++      zone_dma_bits = 31;
+       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+       max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -8,6 +8,8 @@
+ static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
++extern unsigned int zone_dma_bits;
++
+ #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
+ #include <asm/dma-direct.h>
+ #else
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -16,12 +16,11 @@
+ #include <linux/swiotlb.h>
+ /*
+- * Most architectures use ZONE_DMA for the first 16 Megabytes, but
+- * some use it for entirely different regions:
++ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it
++ * it for entirely different regions. In that case the arch code needs to
++ * override the variable below for dma-direct to work properly.
+  */
+-#ifndef ARCH_ZONE_DMA_BITS
+-#define ARCH_ZONE_DMA_BITS 24
+-#endif
++unsigned int zone_dma_bits __ro_after_init = 24;
+ static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
+ {
+@@ -69,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_ma
+        * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
+        * zones.
+        */
+-      if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
++      if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
+               return GFP_DMA;
+       if (*phys_mask <= DMA_BIT_MASK(32))
+               return GFP_DMA32;
+@@ -395,7 +394,7 @@ int dma_direct_supported(struct device *
+       u64 min_mask;
+       if (IS_ENABLED(CONFIG_ZONE_DMA))
+-              min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS);
++              min_mask = DMA_BIT_MASK(zone_dma_bits);
+       else
+               min_mask = DMA_BIT_MASK(30);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch
new file mode 100644 (file)
index 0000000..51fd4be
--- /dev/null
@@ -0,0 +1,259 @@
+From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Thu, 7 Nov 2019 16:06:45 +0100
+Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation
+
+commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream.
+
+The devices found behind this PCIe chip have unusual DMA mapping
+constraints as there is an AMBA interconnect placed in between them and
+the different PCI endpoints. The offset between physical memory
+addresses and AMBA's view is provided by reading a PCI config register,
+which is saved and used whenever DMA mapping is needed.
+
+It turns out that this DMA setup can be represented by properly setting
+'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device
+enable fixup. And ultimately allows us to get rid of this device's
+custom DMA functions.
+
+Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is
+moved to avoid warnings whenever CONFIG_PM is not enabled.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/x86/Kconfig                  |   1 -
+ arch/x86/include/asm/device.h     |   3 -
+ arch/x86/include/asm/dma-direct.h |   9 --
+ arch/x86/pci/sta2x11-fixup.c      | 135 ++++++------------------------
+ 4 files changed, 26 insertions(+), 122 deletions(-)
+ delete mode 100644 arch/x86/include/asm/dma-direct.h
+
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE
+ config STA2X11
+       bool "STA2X11 Companion Chip Support"
+       depends on X86_32_NON_STANDARD && PCI
+-      select ARCH_HAS_PHYS_TO_DMA
+       select SWIOTLB
+       select MFD_STA2X11
+       select GPIOLIB
+--- a/arch/x86/include/asm/device.h
++++ b/arch/x86/include/asm/device.h
+@@ -6,9 +6,6 @@ struct dev_archdata {
+ #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
+       void *iommu; /* hook for IOMMU specific extension */
+ #endif
+-#ifdef CONFIG_STA2X11
+-      bool is_sta2x11;
+-#endif
+ };
+ #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
+--- a/arch/x86/include/asm/dma-direct.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-#ifndef ASM_X86_DMA_DIRECT_H
+-#define ASM_X86_DMA_DIRECT_H 1
+-
+-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
+-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr);
+-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr);
+-
+-#endif /* ASM_X86_DMA_DIRECT_H */
+--- a/arch/x86/pci/sta2x11-fixup.c
++++ b/arch/x86/pci/sta2x11-fixup.c
+@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin
+ };
+ struct sta2x11_mapping {
+-      u32 amba_base;
+       int is_suspended;
+       struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS];
+ };
+@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci
+       return pdev->bus->number - instance->bus0;
+ }
+-static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
+-{
+-      struct sta2x11_instance *instance;
+-      int ep;
+-
+-      instance = sta2x11_pdev_to_instance(pdev);
+-      if (!instance)
+-              return NULL;
+-      ep = sta2x11_pdev_to_ep(pdev);
+-      return instance->map + ep;
+-}
+-
+ /* This is exported, as some devices need to access the MFD registers */
+ struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev)
+ {
+@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins
+ }
+ EXPORT_SYMBOL(sta2x11_get_instance);
+-
+-/**
+- * p2a - Translate physical address to STA2x11 AMBA address,
+- *       used for DMA transfers to STA2x11
+- * @p: Physical address
+- * @pdev: PCI device (must be hosted within the connext)
+- */
+-static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev)
+-{
+-      struct sta2x11_mapping *map;
+-      dma_addr_t a;
+-
+-      map = sta2x11_pdev_to_mapping(pdev);
+-      a = p + map->amba_base;
+-      return a;
+-}
+-
+-/**
+- * a2p - Translate STA2x11 AMBA address to physical address
+- *       used for DMA transfers from STA2x11
+- * @a: STA2x11 AMBA address
+- * @pdev: PCI device (must be hosted within the connext)
+- */
+-static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev)
+-{
+-      struct sta2x11_mapping *map;
+-      dma_addr_t p;
+-
+-      map = sta2x11_pdev_to_mapping(pdev);
+-      p = a - map->amba_base;
+-      return p;
+-}
+-
+ /* At setup time, we use our own ops if the device is a ConneXt one */
+ static void sta2x11_setup_pdev(struct pci_dev *pdev)
+ {
+@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc
+       if (!instance) /* either a sta2x11 bridge or another ST device */
+               return;
+-      pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+-      pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+-      pdev->dev.archdata.is_sta2x11 = true;
+       /* We must enable all devices as master, for audio DMA to work */
+       pci_set_master(pdev);
+@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc
+ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev);
+ /*
+- * The following three functions are exported (used in swiotlb: FIXME)
+- */
+-/**
+- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it)
+- * @dev: device for a PCI device
+- * @addr: DMA address
+- * @size: DMA size
+- */
+-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+-      struct sta2x11_mapping *map;
+-
+-      if (!dev->archdata.is_sta2x11) {
+-              if (!dev->dma_mask)
+-                      return false;
+-              return addr + size - 1 <= *dev->dma_mask;
+-      }
+-
+-      map = sta2x11_pdev_to_mapping(to_pci_dev(dev));
+-
+-      if (!map || (addr < map->amba_base))
+-              return false;
+-      if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) {
+-              return false;
+-      }
+-
+-      return true;
+-}
+-
+-/**
+- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device
+- * @dev: device for a PCI device
+- * @paddr: Physical address
+- */
+-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+-{
+-      if (!dev->archdata.is_sta2x11)
+-              return paddr;
+-      return p2a(paddr, to_pci_dev(dev));
+-}
+-
+-/**
+- * dma_to_phys - Return the physical address used for this STA2x11 DMA address
+- * @dev: device for a PCI device
+- * @daddr: STA2x11 AMBA DMA address
+- */
+-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
+-{
+-      if (!dev->archdata.is_sta2x11)
+-              return daddr;
+-      return a2p(daddr, to_pci_dev(dev));
+-}
+-
+-
+-/*
+  * At boot we must set up the mappings for the pcie-to-amba bridge.
+  * It involves device access, and the same happens at suspend/resume time
+  */
+@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device
+ /* At probe time, enable mapping for each endpoint, using the pdev */
+ static void sta2x11_map_ep(struct pci_dev *pdev)
+ {
+-      struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
++      struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev);
++      struct device *dev = &pdev->dev;
++      u32 amba_base, max_amba_addr;
+       int i;
+-      if (!map)
++      if (!instance)
+               return;
+-      pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base);
++
++      pci_read_config_dword(pdev, AHB_BASE(0), &amba_base);
++      max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1;
++
++      dev->dma_pfn_offset = PFN_DOWN(-amba_base);
++
++      dev->bus_dma_mask = max_amba_addr;
++      pci_set_consistent_dma_mask(pdev, max_amba_addr);
++      pci_set_dma_mask(pdev, max_amba_addr);
+       /* Configure AHB mapping */
+       pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0);
+@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de
+       dev_info(&pdev->dev,
+                "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n",
+-               sta2x11_pdev_to_ep(pdev),  map->amba_base,
+-               map->amba_base + STA2X11_AMBA_SIZE - 1);
++               sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr);
+ }
+ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep);
+ #ifdef CONFIG_PM /* Some register values must be saved and restored */
++static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
++{
++      struct sta2x11_instance *instance;
++      int ep;
++
++      instance = sta2x11_pdev_to_instance(pdev);
++      if (!instance)
++              return NULL;
++      ep = sta2x11_pdev_to_ep(pdev);
++      return instance->map + ep;
++}
++
+ static void suspend_mapping(struct pci_dev *pdev)
+ {
+       struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch
new file mode 100644 (file)
index 0000000..0d74bc5
--- /dev/null
@@ -0,0 +1,427 @@
+From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 30 Oct 2019 17:30:57 -0500
+Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers
+
+Extend devm_of_pci_get_host_bridge_resources() and
+pci_parse_request_of_pci_ranges() helpers to also parse the inbound
+addresses from DT 'dma-ranges' and populate a resource list with the
+translated addresses. This will help ensure 'dma-ranges' is always
+parsed in a consistent way.
+
+Tested-by: Srinath Mannam <srinath.mannam@broadcom.com>
+Tested-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> # for AArdvark
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Srinath Mannam <srinath.mannam@broadcom.com>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+Acked-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Jingoo Han <jingoohan1@gmail.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Toan Le <toan@os.amperecomputing.com>
+Cc: Ley Foon Tan <lftan@altera.com>
+Cc: Tom Joseph <tjoseph@cadence.com>
+Cc: Ray Jui <rjui@broadcom.com>
+Cc: Scott Branden <sbranden@broadcom.com>
+Cc: bcm-kernel-feedback-list@broadcom.com
+Cc: Ryder Lee <ryder.lee@mediatek.com>
+Cc: Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
+Cc: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Cc: Simon Horman <horms@verge.net.au>
+Cc: Shawn Lin <shawn.lin@rock-chips.com>
+Cc: Heiko Stuebner <heiko@sntech.de>
+Cc: Michal Simek <michal.simek@xilinx.com>
+Cc: rfi@lists.rocketboards.org
+Cc: linux-mediatek@lists.infradead.org
+Cc: linux-renesas-soc@vger.kernel.org
+Cc: linux-rockchip@lists.infradead.org
+(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc)
+---
+ .../pci/controller/dwc/pcie-designware-host.c |  8 +--
+ drivers/pci/controller/pci-aardvark.c         |  3 +-
+ drivers/pci/controller/pci-ftpci100.c         |  4 +-
+ drivers/pci/controller/pci-host-common.c      |  2 +-
+ drivers/pci/controller/pci-v3-semi.c          |  8 +--
+ drivers/pci/controller/pci-versatile.c        |  3 +-
+ drivers/pci/controller/pci-xgene.c            |  4 +-
+ drivers/pci/controller/pcie-altera.c          |  5 +-
+ drivers/pci/controller/pcie-cadence-host.c    |  2 +-
+ drivers/pci/controller/pcie-iproc-platform.c  |  4 +-
+ drivers/pci/controller/pcie-mediatek.c        |  4 +-
+ drivers/pci/controller/pcie-mobiveil.c        |  4 +-
+ drivers/pci/controller/pcie-rcar.c            |  3 +-
+ drivers/pci/controller/pcie-rockchip-host.c   |  4 +-
+ drivers/pci/controller/pcie-xilinx-nwl.c      |  4 +-
+ drivers/pci/controller/pcie-xilinx.c          |  4 +-
+ drivers/pci/of.c                              | 61 ++++++++++++++++---
+ drivers/pci/pci.h                             |  8 ++-
+ include/linux/pci.h                           |  9 ++-
+ 19 files changed, 96 insertions(+), 48 deletions(-)
+
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -343,12 +343,8 @@ int dw_pcie_host_init(struct pcie_port *
+       if (!bridge)
+               return -ENOMEM;
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+-                                      &bridge->windows, &pp->io_base);
+-      if (ret)
+-              return ret;
+-
+-      ret = devm_request_pci_bus_resources(dev, &bridge->windows);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (ret)
+               return ret;
+--- a/drivers/pci/controller/pci-aardvark.c
++++ b/drivers/pci/controller/pci-aardvark.c
+@@ -1023,7 +1023,8 @@ static int advk_pcie_probe(struct platfo
+               return ret;
+       }
+-      ret = advk_pcie_parse_request_of_pci_ranges(pcie);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, &bus);
+       if (ret) {
+               dev_err(dev, "Failed to parse resources\n");
+               return ret;
+--- a/drivers/pci/controller/pci-ftpci100.c
++++ b/drivers/pci/controller/pci-ftpci100.c
+@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat
+       if (IS_ERR(p->base))
+               return PTR_ERR(p->base);
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+-                                                  &res, &io_base);
++      ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
++                                            &host->dma_ranges, NULL);
+       if (ret)
+               return ret;
+--- a/drivers/pci/controller/pci-host-common.c
++++ b/drivers/pci/controller/pci-host-common.c
+@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci
+       struct pci_config_window *cfg;
+       /* Parse our PCI ranges and request their resources */
+-      err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
++      err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+       if (err)
+               return ERR_PTR(err);
+--- a/drivers/pci/controller/pci-v3-semi.c
++++ b/drivers/pci/controller/pci-v3-semi.c
+@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_
+       if (IS_ERR(v3->config_base))
+               return PTR_ERR(v3->config_base);
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+-                                                  &io_base);
+-      if (ret)
+-              return ret;
+-
+-      ret = devm_request_pci_bus_resources(dev, &res);
++      ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
++                                            &host->dma_ranges, NULL);
+       if (ret)
+               return ret;
+--- a/drivers/pci/controller/pci-versatile.c
++++ b/drivers/pci/controller/pci-versatile.c
+@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl
+       if (IS_ERR(versatile_cfg_base[1]))
+               return PTR_ERR(versatile_cfg_base[1]);
+-      ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            NULL, NULL);
+       if (ret)
+               return ret;
+--- a/drivers/pci/controller/pci-xgene.c
++++ b/drivers/pci/controller/pci-xgene.c
+@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf
+       if (ret)
+               return ret;
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+-                                                  &iobase);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (ret)
+               return ret;
+--- a/drivers/pci/controller/pcie-altera.c
++++ b/drivers/pci/controller/pcie-altera.c
+@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat
+               return ret;
+       }
+-      INIT_LIST_HEAD(&pcie->resources);
+-
+-      ret = altera_pcie_parse_request_of_pci_ranges(pcie);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (ret) {
+               dev_err(dev, "Failed add resources\n");
+               return ret;
+--- a/drivers/pci/controller/pcie-cadence-host.c
++++ b/drivers/pci/controller/pcie-cadence-host.c
+@@ -211,7 +211,7 @@ static int cdns_pcie_host_init(struct de
+       int err;
+       /* Parse our PCI ranges and request their resources */
+-      err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
++      err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+       if (err)
+               return err;
+--- a/drivers/pci/controller/pcie-iproc-platform.c
++++ b/drivers/pci/controller/pcie-iproc-platform.c
+@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct
+       if (IS_ERR(pcie->phy))
+               return PTR_ERR(pcie->phy);
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources,
+-                                                  &iobase);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (ret) {
+               dev_err(dev, "unable to get PCI host bridge resources\n");
+               return ret;
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci
+       resource_size_t io_base;
+       int err;
+-      err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+-                                                  windows, &io_base);
++      err = pci_parse_request_of_pci_ranges(dev, windows,
++                                            &host->dma_ranges, &bus);
+       if (err)
+               return err;
+--- a/drivers/pci/controller/pcie-mobiveil.c
++++ b/drivers/pci/controller/pcie-mobiveil.c
+@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl
+       INIT_LIST_HEAD(&pcie->resources);
+       /* parse the host bridge base addresses from the device tree file */
+-      ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+-                                                  &pcie->resources, &iobase);
++      ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (ret) {
+               dev_err(dev, "Getting bridge resources failed\n");
+               return ret;
+--- a/drivers/pci/controller/pcie-rcar.c
++++ b/drivers/pci/controller/pcie-rcar.c
+@@ -1143,7 +1143,8 @@ static int rcar_pcie_probe(struct platfo
+       pcie->dev = dev;
+       platform_set_drvdata(pdev, pcie);
+-      err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
++      err = pci_parse_request_of_pci_ranges(dev, &pcie->resources,
++                                            &bridge->dma_ranges, NULL);
+       if (err)
+               goto err_free_bridge;
+--- a/drivers/pci/controller/pcie-rockchip-host.c
++++ b/drivers/pci/controller/pcie-rockchip-host.c
+@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl
+       if (err < 0)
+               goto err_deinit_port;
+-      err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+-                                                  &res, &io_base);
++      err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, &bus_res);
+       if (err)
+               goto err_remove_irq_domain;
+--- a/drivers/pci/controller/pcie-xilinx-nwl.c
++++ b/drivers/pci/controller/pcie-xilinx-nwl.c
+@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor
+               return err;
+       }
+-      err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+-                                                  &iobase);
++      err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (err) {
+               dev_err(dev, "Getting bridge resources failed\n");
+               return err;
+--- a/drivers/pci/controller/pcie-xilinx.c
++++ b/drivers/pci/controller/pcie-xilinx.c
+@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat
+               return err;
+       }
+-      err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+-                                                  &iobase);
++      err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
+       if (err) {
+               dev_err(dev, "Getting bridge resources failed\n");
+               return err;
+--- a/drivers/pci/of.c
++++ b/drivers/pci/of.c
+@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl
+  */
+ int devm_of_pci_get_host_bridge_resources(struct device *dev,
+                       unsigned char busno, unsigned char bus_max,
+-                      struct list_head *resources, resource_size_t *io_base)
++                      struct list_head *resources,
++                      struct list_head *ib_resources,
++                      resource_size_t *io_base)
+ {
+       struct device_node *dev_node = dev->of_node;
+       struct resource *res, tmp_res;
+       struct resource *bus_range;
+       struct of_pci_range range;
+       struct of_pci_range_parser parser;
+-      char range_type[4];
++      const char *range_type;
+       int err;
+       if (io_base)
+@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource
+       for_each_of_pci_range(&parser, &range) {
+               /* Read next ranges element */
+               if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
+-                      snprintf(range_type, 4, " IO");
++                      range_type = "IO";
+               else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
+-                      snprintf(range_type, 4, "MEM");
++                      range_type = "MEM";
+               else
+-                      snprintf(range_type, 4, "err");
+-              dev_info(dev, "  %s %#010llx..%#010llx -> %#010llx\n",
++                      range_type = "err";
++              dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
+                        range_type, range.cpu_addr,
+                        range.cpu_addr + range.size - 1, range.pci_addr);
+@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource
+               pci_add_resource_offset(resources, res, res->start - range.pci_addr);
+       }
++      /* Check for dma-ranges property */
++      if (!ib_resources)
++              return 0;
++      err = of_pci_dma_range_parser_init(&parser, dev_node);
++      if (err)
++              return 0;
++
++      dev_dbg(dev, "Parsing dma-ranges property...\n");
++      for_each_of_pci_range(&parser, &range) {
++              struct resource_entry *entry;
++              /*
++               * If we failed translation or got a zero-sized region
++               * then skip this range
++               */
++              if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) ||
++                  range.cpu_addr == OF_BAD_ADDR || range.size == 0)
++                      continue;
++
++              dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
++                       "IB MEM", range.cpu_addr,
++                       range.cpu_addr + range.size - 1, range.pci_addr);
++
++
++              err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
++              if (err)
++                      continue;
++
++              res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
++              if (!res) {
++                      err = -ENOMEM;
++                      goto failed;
++              }
++
++              /* Keep the resource list sorted */
++              resource_list_for_each_entry(entry, ib_resources)
++                      if (entry->res->start > res->start)
++                              break;
++
++              pci_add_resource_offset(&entry->node, res,
++                                      res->start - range.pci_addr);
++      }
++
+       return 0;
+ failed:
+@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p
+ int pci_parse_request_of_pci_ranges(struct device *dev,
+                                   struct list_head *resources,
++                                  struct list_head *ib_resources,
+                                   struct resource **bus_range)
+ {
+       int err, res_valid = 0;
+@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru
+       struct resource_entry *win, *tmp;
+       INIT_LIST_HEAD(resources);
++      if (ib_resources)
++              INIT_LIST_HEAD(ib_resources);
+       err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
+-                                                  &iobase);
++                                                  ib_resources, &iobase);
+       if (err)
+               return err;
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -636,11 +636,15 @@ static inline void pci_release_bus_of_no
+ #if defined(CONFIG_OF_ADDRESS)
+ int devm_of_pci_get_host_bridge_resources(struct device *dev,
+                       unsigned char busno, unsigned char bus_max,
+-                      struct list_head *resources, resource_size_t *io_base);
++                      struct list_head *resources,
++                      struct list_head *ib_resources,
++                      resource_size_t *io_base);
+ #else
+ static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
+                       unsigned char busno, unsigned char bus_max,
+-                      struct list_head *resources, resource_size_t *io_base)
++                      struct list_head *resources,
++                      struct list_head *ib_resources,
++                      resource_size_t *io_base)
+ {
+       return -EINVAL;
+ }
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -2278,6 +2278,7 @@ struct irq_domain;
+ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus);
+ int pci_parse_request_of_pci_ranges(struct device *dev,
+                                   struct list_head *resources,
++                                  struct list_head *ib_resources,
+                                   struct resource **bus_range);
+ /* Arch may override this (weak) */
+@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n
+ #else /* CONFIG_OF */
+ static inline struct irq_domain *
+ pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
+-static inline int pci_parse_request_of_pci_ranges(struct device *dev,
+-                                                struct list_head *resources,
+-                                                struct resource **bus_range)
++static inline int
++pci_parse_request_of_pci_ranges(struct device *dev,
++                              struct list_head *resources,
++                              struct list_head *ib_resources,
++                              struct resource **bus_range)
+ {
+       return -EINVAL;
+ }
diff --git a/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch
new file mode 100644 (file)
index 0000000..d115f0e
--- /dev/null
@@ -0,0 +1,103 @@
+From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 12 Nov 2019 17:06:04 +0100
+Subject: [PATCH] dma-direct: unify the dma_capable definitions
+
+commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream.
+
+Currently each architectures that wants to override dma_to_phys and
+phys_to_dma also has to provide dma_capable.  But there isn't really
+any good reason for that.  powerpc and mips just have copies of the
+generic one minus the latests fix, and the arm one was the inspiration
+for said fix, but misses the bus_dma_mask handling.
+Make all architectures use the generic version instead.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+---
+ arch/arm/include/asm/dma-direct.h     | 19 -------------------
+ arch/mips/include/asm/dma-direct.h    |  8 --------
+ arch/powerpc/include/asm/dma-direct.h |  9 ---------
+ include/linux/dma-direct.h            |  2 +-
+ 4 files changed, 1 insertion(+), 37 deletions(-)
+
+--- a/arch/arm/include/asm/dma-direct.h
++++ b/arch/arm/include/asm/dma-direct.h
+@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys(
+       return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset;
+ }
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+-      u64 limit, mask;
+-
+-      if (!dev->dma_mask)
+-              return 0;
+-
+-      mask = *dev->dma_mask;
+-
+-      limit = (mask + 1) & ~mask;
+-      if (limit && size > limit)
+-              return 0;
+-
+-      if ((addr | (addr + size - 1)) & ~mask)
+-              return 0;
+-
+-      return 1;
+-}
+-
+ #endif /* ASM_ARM_DMA_DIRECT_H */
+--- a/arch/mips/include/asm/dma-direct.h
++++ b/arch/mips/include/asm/dma-direct.h
+@@ -2,14 +2,6 @@
+ #ifndef _MIPS_DMA_DIRECT_H
+ #define _MIPS_DMA_DIRECT_H 1
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+-      if (!dev->dma_mask)
+-              return false;
+-
+-      return addr + size - 1 <= *dev->dma_mask;
+-}
+-
+ dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr);
+ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr);
+--- a/arch/powerpc/include/asm/dma-direct.h
++++ b/arch/powerpc/include/asm/dma-direct.h
+@@ -2,15 +2,6 @@
+ #ifndef ASM_POWERPC_DMA_DIRECT_H
+ #define ASM_POWERPC_DMA_DIRECT_H 1
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+-      if (!dev->dma_mask)
+-              return false;
+-
+-      return addr + size - 1 <=
+-              min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+-}
+-
+ static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+ {
+       if (!dev)
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys(
+       return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT);
+ }
++#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+ {
+@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de
+       return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+ }
+-#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+ #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ bool force_dma_unencrypted(struct device *dev);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch
new file mode 100644 (file)
index 0000000..a98f1d3
--- /dev/null
@@ -0,0 +1,69 @@
+From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 12 Nov 2019 17:07:43 +0100
+Subject: [PATCH] dma-direct: avoid a forward declaration for
+ phys_to_dma
+
+Move dma_capable down a bit so that we don't need a forward declaration
+for phys_to_dma.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2)
+---
+ include/linux/dma-direct.h | 30 ++++++++++++++----------------
+ 1 file changed, 14 insertions(+), 16 deletions(-)
+
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -6,8 +6,6 @@
+ #include <linux/memblock.h> /* for min_low_pfn */
+ #include <linux/mem_encrypt.h>
+-static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+-
+ extern unsigned int zone_dma_bits;
+ #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
+@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys(
+ }
+ #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+-      dma_addr_t end = addr + size - 1;
+-
+-      if (!dev->dma_mask)
+-              return false;
+-
+-      if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
+-          min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+-              return false;
+-
+-      return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+-}
+-
+ #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ bool force_dma_unencrypted(struct device *dev);
+ #else
+@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st
+       return __sme_clr(__dma_to_phys(dev, daddr));
+ }
++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
++{
++      dma_addr_t end = addr + size - 1;
++
++      if (!dev->dma_mask)
++              return false;
++
++      if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
++          min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
++              return false;
++
++      return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
++}
++
+ u64 dma_direct_get_required_mask(struct device *dev);
+ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t gfp, unsigned long attrs);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch
new file mode 100644 (file)
index 0000000..94a1329
--- /dev/null
@@ -0,0 +1,115 @@
+From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 19 Nov 2019 17:38:58 +0100
+Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the
+ min_low_pfn check
+
+commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream.
+
+The valid memory address check in dma_capable only makes sense when mapping
+normal memory, not when using dma_map_resource to map a device resource.
+Add a new boolean argument to dma_capable to exclude that check for the
+dma_map_resource case.
+
+Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses")
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+---
+ arch/x86/kernel/amd_gart_64.c | 4 ++--
+ drivers/xen/swiotlb-xen.c     | 4 ++--
+ include/linux/dma-direct.h    | 5 +++--
+ kernel/dma/direct.c           | 4 ++--
+ kernel/dma/swiotlb.c          | 2 +-
+ 5 files changed, 10 insertions(+), 9 deletions(-)
+
+--- a/arch/x86/kernel/amd_gart_64.c
++++ b/arch/x86/kernel/amd_gart_64.c
+@@ -185,13 +185,13 @@ static void iommu_full(struct device *de
+ static inline int
+ need_iommu(struct device *dev, unsigned long addr, size_t size)
+ {
+-      return force_iommu || !dma_capable(dev, addr, size);
++      return force_iommu || !dma_capable(dev, addr, size, true);
+ }
+ static inline int
+ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
+ {
+-      return !dma_capable(dev, addr, size);
++      return !dma_capable(dev, addr, size, true);
+ }
+ /* Map a single continuous physical area into the IOMMU.
+--- a/drivers/xen/swiotlb-xen.c
++++ b/drivers/xen/swiotlb-xen.c
+@@ -375,7 +375,7 @@ static dma_addr_t xen_swiotlb_map_page(s
+        * we can safely return the device addr and not worry about bounce
+        * buffering it.
+        */
+-      if (dma_capable(dev, dev_addr, size) &&
++      if (dma_capable(dev, dev_addr, size, true) &&
+           !range_straddles_page_boundary(phys, size) &&
+               !xen_arch_need_swiotlb(dev, phys, dev_addr) &&
+               swiotlb_force != SWIOTLB_FORCE)
+@@ -397,7 +397,7 @@ static dma_addr_t xen_swiotlb_map_page(s
+       /*
+        * Ensure that the address returned is DMA'ble
+        */
+-      if (unlikely(!dma_capable(dev, dev_addr, size))) {
++      if (unlikely(!dma_capable(dev, dev_addr, size, true))) {
+               swiotlb_tbl_unmap_single(dev, map, size, size, dir,
+                               attrs | DMA_ATTR_SKIP_CPU_SYNC);
+               return DMA_MAPPING_ERROR;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st
+       return __sme_clr(__dma_to_phys(dev, daddr));
+ }
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size,
++              bool is_ram)
+ {
+       dma_addr_t end = addr + size - 1;
+       if (!dev->dma_mask)
+               return false;
+-      if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
++      if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
+           min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+               return false;
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -325,7 +325,7 @@ static inline bool dma_direct_possible(s
+               size_t size)
+ {
+       return swiotlb_force != SWIOTLB_FORCE &&
+-              dma_capable(dev, dma_addr, size);
++              dma_capable(dev, dma_addr, size, true);
+ }
+ dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
+@@ -374,7 +374,7 @@ dma_addr_t dma_direct_map_resource(struc
+ {
+       dma_addr_t dma_addr = paddr;
+-      if (unlikely(!dma_capable(dev, dma_addr, size))) {
++      if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
+               report_addr(dev, dma_addr, size);
+               return DMA_MAPPING_ERROR;
+       }
+--- a/kernel/dma/swiotlb.c
++++ b/kernel/dma/swiotlb.c
+@@ -678,7 +678,7 @@ bool swiotlb_map(struct device *dev, phy
+       /* Ensure that the address returned is DMA'ble */
+       *dma_addr = __phys_to_dma(dev, *phys);
+-      if (unlikely(!dma_capable(dev, *dma_addr, size))) {
++      if (unlikely(!dma_capable(dev, *dma_addr, size, true))) {
+               swiotlb_tbl_unmap_single(dev, *phys, size, size, dir,
+                       attrs | DMA_ATTR_SKIP_CPU_SYNC);
+               return false;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch
new file mode 100644 (file)
index 0000000..05dad5d
--- /dev/null
@@ -0,0 +1,366 @@
+From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Thu, 21 Nov 2019 10:26:44 +0100
+Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit
+
+commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream.
+
+Using a mask to represent bus DMA constraints has a set of limitations.
+The biggest one being it can only hold a power of two (minus one). The
+DMA mapping code is already aware of this and treats dev->bus_dma_mask
+as a limit. This quirk is already used by some architectures although
+still rare.
+
+With the introduction of the Raspberry Pi 4 we've found a new contender
+for the use of bus DMA limits, as its PCIe bus can only address the
+lower 3GB of memory (of a total of 4GB). This is impossible to represent
+with a mask. To make things worse the device-tree code rounds non power
+of two bus DMA limits to the next power of two, which is unacceptable in
+this case.
+
+In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all
+over the tree and treat it as such. Note that dev->bus_dma_limit should
+contain the higher accessible DMA address.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Robin Murphy <robin.murphy@arm.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/mips/pci/fixup-sb1250.c  | 16 ++++++++--------
+ arch/powerpc/sysdev/fsl_pci.c |  6 +++---
+ arch/x86/kernel/pci-dma.c     |  2 +-
+ arch/x86/mm/mem_encrypt.c     |  2 +-
+ arch/x86/pci/sta2x11-fixup.c  |  2 +-
+ drivers/acpi/arm64/iort.c     | 20 +++++++-------------
+ drivers/ata/ahci.c            |  2 +-
+ drivers/iommu/dma-iommu.c     |  3 +--
+ drivers/of/device.c           |  9 +++++----
+ include/linux/device.h        |  6 +++---
+ include/linux/dma-direct.h    |  2 +-
+ include/linux/dma-mapping.h   |  2 +-
+ kernel/dma/direct.c           | 27 +++++++++++++--------------
+ 13 files changed, 46 insertions(+), 53 deletions(-)
+
+--- a/arch/mips/pci/fixup-sb1250.c
++++ b/arch/mips/pci/fixup-sb1250.c
+@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI
+ /*
+  * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit
+- * bus, so we set the bus's DMA mask accordingly.  However the HT link
++ * bus, so we set the bus's DMA limit accordingly.  However the HT link
+  * down the artificial PCI-HT bridge supports 40-bit addressing and the
+  * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus
+  * width, so we record the PCI-HT bridge's secondary and subordinate bus
+- * numbers and do not set the mask for devices present in the inclusive
++ * numbers and do not set the limit for devices present in the inclusive
+  * range of those.
+  */
+-struct sb1250_bus_dma_mask_exclude {
++struct sb1250_bus_dma_limit_exclude {
+       bool set;
+       unsigned char start;
+       unsigned char end;
+ };
+-static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data)
++static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data)
+ {
+-      struct sb1250_bus_dma_mask_exclude *exclude = data;
++      struct sb1250_bus_dma_limit_exclude *exclude = data;
+       bool exclude_this;
+       bool ht_bridge;
+@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc
+                       exclude->start, exclude->end);
+       } else {
+               dev_dbg(&dev->dev, "disabling DAC for device");
+-              dev->dev.bus_dma_mask = DMA_BIT_MASK(32);
++              dev->dev.bus_dma_limit = DMA_BIT_MASK(32);
+       }
+       return 0;
+@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc
+ static void quirk_sb1250_pci_dac(struct pci_dev *dev)
+ {
+-      struct sb1250_bus_dma_mask_exclude exclude = { .set = false };
++      struct sb1250_bus_dma_limit_exclude exclude = { .set = false };
+-      pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude);
++      pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude);
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
+                       quirk_sb1250_pci_dac);
+--- a/arch/powerpc/sysdev/fsl_pci.c
++++ b/arch/powerpc/sysdev/fsl_pci.c
+@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st
+ {
+       struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+-      pdev->dev.bus_dma_mask =
+-              hose->dma_window_base_cur + hose->dma_window_size;
++      pdev->dev.bus_dma_limit =
++              hose->dma_window_base_cur + hose->dma_window_size - 1;
+ }
+ static void setup_swiotlb_ops(struct pci_controller *hose)
+@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct
+        * mapping that allows addressing any RAM address from across PCI.
+        */
+       if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) {
+-              dev->bus_dma_mask = 0;
++              dev->bus_dma_limit = 0;
+               dev->archdata.dma_offset = pci64_dma_offset;
+       }
+ }
+--- a/arch/x86/kernel/pci-dma.c
++++ b/arch/x86/kernel/pci-dma.c
+@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init);
+ static int via_no_dac_cb(struct pci_dev *pdev, void *data)
+ {
+-      pdev->dev.bus_dma_mask = DMA_BIT_MASK(32);
++      pdev->dev.bus_dma_limit = DMA_BIT_MASK(32);
+       return 0;
+ }
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device
+       if (sme_active()) {
+               u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask));
+               u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask,
+-                                              dev->bus_dma_mask);
++                                              dev->bus_dma_limit);
+               if (dma_dev_mask <= dma_enc_mask)
+                       return true;
+--- a/arch/x86/pci/sta2x11-fixup.c
++++ b/arch/x86/pci/sta2x11-fixup.c
+@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de
+       dev->dma_pfn_offset = PFN_DOWN(-amba_base);
+-      dev->bus_dma_mask = max_amba_addr;
++      dev->bus_dma_limit = max_amba_addr;
+       pci_set_consistent_dma_mask(pdev, max_amba_addr);
+       pci_set_dma_mask(pdev, max_amba_addr);
+--- a/drivers/acpi/arm64/iort.c
++++ b/drivers/acpi/arm64/iort.c
+@@ -1057,8 +1057,8 @@ static int rc_dma_get_range(struct devic
+  */
+ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+ {
+-      u64 mask, dmaaddr = 0, size = 0, offset = 0;
+-      int ret, msb;
++      u64 end, mask, dmaaddr = 0, size = 0, offset = 0;
++      int ret;
+       /*
+        * If @dev is expected to be DMA-capable then the bus code that created
+@@ -1085,19 +1085,13 @@ void iort_dma_setup(struct device *dev,
+       }
+       if (!ret) {
+-              msb = fls64(dmaaddr + size - 1);
+               /*
+-               * Round-up to the power-of-two mask or set
+-               * the mask to the whole 64-bit address space
+-               * in case the DMA region covers the full
+-               * memory window.
++               * Limit coherent and dma mask based on size retrieved from
++               * firmware.
+                */
+-              mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1;
+-              /*
+-               * Limit coherent and dma mask based on size
+-               * retrieved from firmware.
+-               */
+-              dev->bus_dma_mask = mask;
++              end = dmaaddr + size - 1;
++              mask = DMA_BIT_MASK(ilog2(end) + 1);
++              dev->bus_dma_limit = end;
+               dev->coherent_dma_mask = mask;
+               *dev->dma_mask = mask;
+       }
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -899,7 +899,7 @@ static int ahci_configure_dma_masks(stru
+        * value, don't extend it here. This happens on STA2X11, for example.
+        *
+        * XXX: manipulating the DMA mask from platform code is completely
+-       * bogus, platform code should use dev->bus_dma_mask instead..
++       * bogus, platform code should use dev->bus_dma_limit instead..
+        */
+       if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
+               return 0;
+--- a/drivers/iommu/dma-iommu.c
++++ b/drivers/iommu/dma-iommu.c
+@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s
+       if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+               iova_len = roundup_pow_of_two(iova_len);
+-      if (dev->bus_dma_mask)
+-              dma_limit &= dev->bus_dma_mask;
++      dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit);
+       if (domain->geometry.force_aperture)
+               dma_limit = min(dma_limit, domain->geometry.aperture_end);
+--- a/drivers/of/device.c
++++ b/drivers/of/device.c
+@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev,
+       bool coherent;
+       unsigned long offset;
+       const struct iommu_ops *iommu;
+-      u64 mask;
++      u64 mask, end;
+       ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
+       if (ret < 0) {
+@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev,
+        * Limit coherent and dma mask based on size and default mask
+        * set by the driver.
+        */
+-      mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1);
++      end = dma_addr + size - 1;
++      mask = DMA_BIT_MASK(ilog2(end) + 1);
+       dev->coherent_dma_mask &= mask;
+       *dev->dma_mask &= mask;
+-      /* ...but only set bus mask if we found valid dma-ranges earlier */
++      /* ...but only set bus limit if we found valid dma-ranges earlier */
+       if (!ret)
+-              dev->bus_dma_mask = mask;
++              dev->bus_dma_limit = end;
+       coherent = of_dma_is_coherent(np);
+       dev_dbg(dev, "device is%sdma coherent\n",
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -1186,8 +1186,8 @@ struct dev_links_info {
+  * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
+  *            hardware supports 64-bit addresses for consistent allocations
+  *            such descriptors.
+- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA
+- *            limit than the device itself supports.
++ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller
++ *            DMA limit than the device itself supports.
+  * @dma_pfn_offset: offset of DMA memory range relatively of RAM
+  * @dma_parms:        A low level driver may set these to teach IOMMU code about
+  *            segment limitations.
+@@ -1270,7 +1270,7 @@ struct device {
+                                            not all hardware supports
+                                            64 bit addresses for consistent
+                                            allocations such descriptors. */
+-      u64             bus_dma_mask;   /* upstream dma_mask constraint */
++      u64             bus_dma_limit;  /* upstream dma constraint */
+       unsigned long   dma_pfn_offset;
+       struct device_dma_parameters *dma_parms;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de
+           min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+               return false;
+-      return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
++      return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit);
+ }
+ u64 dma_direct_get_required_mask(struct device *dev);
+--- a/include/linux/dma-mapping.h
++++ b/include/linux/dma-mapping.h
+@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co
+  */
+ static inline bool dma_addressing_limited(struct device *dev)
+ {
+-      return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) <
++      return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) <
+                           dma_get_required_mask(dev);
+ }
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -26,10 +26,10 @@ static void report_addr(struct device *d
+ {
+       if (!dev->dma_mask) {
+               dev_err_once(dev, "DMA map on device without dma_mask\n");
+-      } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) {
++      } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) {
+               dev_err_once(dev,
+-                      "overflow %pad+%zu of DMA mask %llx bus mask %llx\n",
+-                      &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask);
++                      "overflow %pad+%zu of DMA mask %llx bus limit %llx\n",
++                      &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit);
+       }
+       WARN_ON_ONCE(1);
+ }
+@@ -50,15 +50,14 @@ u64 dma_direct_get_required_mask(struct
+ }
+ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
+-              u64 *phys_mask)
++              u64 *phys_limit)
+ {
+-      if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask)
+-              dma_mask = dev->bus_dma_mask;
++      u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit);
+       if (force_dma_unencrypted(dev))
+-              *phys_mask = __dma_to_phys(dev, dma_mask);
++              *phys_limit = __dma_to_phys(dev, dma_limit);
+       else
+-              *phys_mask = dma_to_phys(dev, dma_mask);
++              *phys_limit = dma_to_phys(dev, dma_limit);
+       /*
+        * Optimistically try the zone that the physical address mask falls
+@@ -68,9 +67,9 @@ static gfp_t __dma_direct_optimal_gfp_ma
+        * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
+        * zones.
+        */
+-      if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
++      if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits))
+               return GFP_DMA;
+-      if (*phys_mask <= DMA_BIT_MASK(32))
++      if (*phys_limit <= DMA_BIT_MASK(32))
+               return GFP_DMA32;
+       return 0;
+ }
+@@ -78,7 +77,7 @@ static gfp_t __dma_direct_optimal_gfp_ma
+ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
+ {
+       return phys_to_dma_direct(dev, phys) + size - 1 <=
+-                      min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask);
++                      min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
+ }
+ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
+@@ -87,7 +86,7 @@ struct page *__dma_direct_alloc_pages(st
+       size_t alloc_size = PAGE_ALIGN(size);
+       int node = dev_to_node(dev);
+       struct page *page = NULL;
+-      u64 phys_mask;
++      u64 phys_limit;
+       if (attrs & DMA_ATTR_NO_WARN)
+               gfp |= __GFP_NOWARN;
+@@ -95,7 +94,7 @@ struct page *__dma_direct_alloc_pages(st
+       /* we always manually zero the memory once we are done: */
+       gfp &= ~__GFP_ZERO;
+       gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
+-                      &phys_mask);
++                      &phys_limit);
+       page = dma_alloc_contiguous(dev, alloc_size, gfp);
+       if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+               dma_free_contiguous(dev, page, alloc_size);
+@@ -109,7 +108,7 @@ again:
+               page = NULL;
+               if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+-                  phys_mask < DMA_BIT_MASK(64) &&
++                  phys_limit < DMA_BIT_MASK(64) &&
+                   !(gfp & (GFP_DMA32 | GFP_DMA))) {
+                       gfp |= GFP_DMA32;
+                       goto again;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch
new file mode 100644 (file)
index 0000000..9f114c1
--- /dev/null
@@ -0,0 +1,56 @@
+From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Mon, 16 Dec 2019 12:01:08 +0100
+Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller
+
+commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream.
+
+This enables bcm2711's PCIe bus, which is hardwired to a VIA
+Technologies XHCI USB 3.0 controller.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++-
+ 1 file changed, 30 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -331,7 +331,36 @@
+               #address-cells = <2>;
+               #size-cells = <1>;
+-              ranges = <0x0 0x7c000000  0x0 0xfc000000  0x03800000>;
++              ranges = <0x0 0x7c000000  0x0 0xfc000000  0x03800000>,
++                       <0x6 0x00000000  0x6 0x00000000  0x40000000>;
++
++              pcie0: pcie@7d500000 {
++                      compatible = "brcm,bcm2711-pcie";
++                      reg = <0x0 0x7d500000 0x9310>;
++                      device_type = "pci";
++                      #address-cells = <3>;
++                      #interrupt-cells = <1>;
++                      #size-cells = <2>;
++                      interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
++                                   <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-names = "pcie", "msi";
++                      interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++                      interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
++                                                      IRQ_TYPE_LEVEL_HIGH>;
++                      msi-controller;
++                      msi-parent = <&pcie0>;
++
++                      ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
++                                0x0 0x04000000>;
++                      /*
++                       * The wrapper around the PCIe block has a bug
++                       * preventing it from accessing beyond the first 3GB of
++                       * memory.
++                       */
++                      dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
++                                    0x0 0xc0000000>;
++                      brcm,enable-ssc;
++              };
+               genet: ethernet@7d580000 {
+                       compatible = "brcm,bcm2711-genet-v5";
diff --git a/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch
new file mode 100644 (file)
index 0000000..ca97a19
--- /dev/null
@@ -0,0 +1,810 @@
+From 4d9470c29736bf81bdb0d21da24cf350b1e99402 Mon Sep 17 00:00:00 2001
+From: Jim Quinlan <james.quinlan@broadcom.com>
+Date: Mon, 16 Dec 2019 12:01:09 +0100
+Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
+ driver
+
+commit c0452137034bda8f686dd9a2e167949bfffd6776 upstream.
+
+This adds a basic driver for Broadcom's STB PCIe controller, for now
+aimed at Raspberry Pi 4's SoC, bcm2711.
+
+Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
+Co-developed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+[lorenzo.pieralisi@arm.com: updated brcm_pcie_get_rc_bar2_size_and_offset()according to https://lore.kernel.org/linux-pci/be8ddb33a7360af1815cf686f77f3f0913d02be3.camel@suse.de]
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+Reviewed-by: Jeremy Linton <jeremy.linton@arm.com>
+---
+ drivers/pci/controller/Kconfig        |   8 +
+ drivers/pci/controller/Makefile       |   1 +
+ drivers/pci/controller/pcie-brcmstb.c | 755 ++++++++++++++++++++++++++
+ 3 files changed, 764 insertions(+)
+ create mode 100644 drivers/pci/controller/pcie-brcmstb.c
+
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -281,6 +281,14 @@ config VMD
+         To compile this driver as a module, choose M here: the
+         module will be called vmd.
++config PCIE_BRCMSTB
++      tristate "Broadcom Brcmstb PCIe host controller"
++      depends on ARCH_BCM2835 || COMPILE_TEST
++      depends on OF
++      help
++        Say Y here to enable PCIe host controller support for
++        Broadcom STB based SoCs, like the Raspberry Pi 4.
++
+ config PCI_HYPERV_INTERFACE
+       tristate "Hyper-V PCI Interface"
+       depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_VMD) += vmd.o
++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y                         += dwc/
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -0,0 +1,755 @@
++// SPDX-License-Identifier: GPL-2.0+
++/* Copyright (C) 2009 - 2019 Broadcom */
++
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/compiler.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/irqdomain.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/log2.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/pci.h>
++#include <linux/printk.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include "../pci.h"
++
++/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
++#define BRCM_PCIE_CAP_REGS                            0x00ac
++
++/* Broadcom STB PCIe Register Offsets */
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1                               0x0188
++#define  PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK        0xc
++#define  PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN                        0x0
++
++#define PCIE_RC_CFG_PRIV1_ID_VAL3                     0x043c
++#define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK    0xffffff
++
++#define PCIE_RC_DL_MDIO_ADDR                          0x1100
++#define PCIE_RC_DL_MDIO_WR_DATA                               0x1104
++#define PCIE_RC_DL_MDIO_RD_DATA                               0x1108
++
++#define PCIE_MISC_MISC_CTRL                           0x4008
++#define  PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK               0x1000
++#define  PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK    0x2000
++#define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK      0x300000
++#define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128               0x0
++#define  PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK           0xf8000000
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO              0x400c
++#define PCIE_MEM_WIN0_LO(win) \
++              PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI              0x4010
++#define PCIE_MEM_WIN0_HI(win) \
++              PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4)
++
++#define PCIE_MISC_RC_BAR1_CONFIG_LO                   0x402c
++#define  PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK                0x1f
++
++#define PCIE_MISC_RC_BAR2_CONFIG_LO                   0x4034
++#define  PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK                0x1f
++#define PCIE_MISC_RC_BAR2_CONFIG_HI                   0x4038
++
++#define PCIE_MISC_RC_BAR3_CONFIG_LO                   0x403c
++#define  PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK                0x1f
++
++#define PCIE_MISC_PCIE_CTRL                           0x4064
++#define  PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK    0x1
++
++#define PCIE_MISC_PCIE_STATUS                         0x4068
++#define  PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK         0x80
++#define  PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK    0x20
++#define  PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK    0x10
++#define  PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK  0x40
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT              0x4070
++#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK  0xfff00000
++#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK   0xfff0
++#define PCIE_MEM_WIN0_BASE_LIMIT(win) \
++              PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI                 0x4080
++#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK      0xff
++#define PCIE_MEM_WIN0_BASE_HI(win)    \
++              PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI                        0x4084
++#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK    0xff
++#define PCIE_MEM_WIN0_LIMIT_HI(win)   \
++              PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
++
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG                                        0x4204
++#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK      0x2
++#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK              0x08000000
++
++#define PCIE_MSI_INTR2_STATUS                         0x4500
++#define PCIE_MSI_INTR2_CLR                            0x4508
++#define PCIE_MSI_INTR2_MASK_SET                               0x4510
++#define PCIE_MSI_INTR2_MASK_CLR                               0x4514
++
++#define PCIE_EXT_CFG_DATA                             0x8000
++
++#define PCIE_EXT_CFG_INDEX                            0x9000
++#define  PCIE_EXT_BUSNUM_SHIFT                                20
++#define  PCIE_EXT_SLOT_SHIFT                          15
++#define  PCIE_EXT_FUNC_SHIFT                          12
++
++#define PCIE_RGR1_SW_INIT_1                           0x9210
++#define  PCIE_RGR1_SW_INIT_1_PERST_MASK                       0x1
++#define  PCIE_RGR1_SW_INIT_1_INIT_MASK                        0x2
++
++/* PCIe parameters */
++#define BRCM_NUM_PCIE_OUT_WINS                0x4
++
++/* MDIO registers */
++#define MDIO_PORT0                    0x0
++#define MDIO_DATA_MASK                        0x7fffffff
++#define MDIO_PORT_MASK                        0xf0000
++#define MDIO_REGAD_MASK                       0xffff
++#define MDIO_CMD_MASK                 0xfff00000
++#define MDIO_CMD_READ                 0x1
++#define MDIO_CMD_WRITE                        0x0
++#define MDIO_DATA_DONE_MASK           0x80000000
++#define MDIO_RD_DONE(x)                       (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
++#define MDIO_WT_DONE(x)                       (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
++#define SSC_REGS_ADDR                 0x1100
++#define SET_ADDR_OFFSET                       0x1f
++#define SSC_CNTL_OFFSET                       0x2
++#define SSC_CNTL_OVRD_EN_MASK         0x8000
++#define SSC_CNTL_OVRD_VAL_MASK                0x4000
++#define SSC_STATUS_OFFSET             0x1
++#define SSC_STATUS_SSC_MASK           0x400
++#define SSC_STATUS_PLL_LOCK_MASK      0x800
++
++/* Internal PCIe Host Controller Information.*/
++struct brcm_pcie {
++      struct device           *dev;
++      void __iomem            *base;
++      struct clk              *clk;
++      struct pci_bus          *root_bus;
++      struct device_node      *np;
++      bool                    ssc;
++      int                     gen;
++};
++
++/*
++ * This is to convert the size of the inbound "BAR" region to the
++ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
++ */
++static int brcm_pcie_encode_ibar_size(u64 size)
++{
++      int log2_in = ilog2(size);
++
++      if (log2_in >= 12 && log2_in <= 15)
++              /* Covers 4KB to 32KB (inclusive) */
++              return (log2_in - 12) + 0x1c;
++      else if (log2_in >= 16 && log2_in <= 35)
++              /* Covers 64KB to 32GB, (inclusive) */
++              return log2_in - 15;
++      /* Something is awry so disable */
++      return 0;
++}
++
++static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd)
++{
++      u32 pkt = 0;
++
++      pkt |= FIELD_PREP(MDIO_PORT_MASK, port);
++      pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad);
++      pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd);
++
++      return pkt;
++}
++
++/* negative return value indicates error */
++static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val)
++{
++      int tries;
++      u32 data;
++
++      writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ),
++                 base + PCIE_RC_DL_MDIO_ADDR);
++      readl(base + PCIE_RC_DL_MDIO_ADDR);
++
++      data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++      for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
++              udelay(10);
++              data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++      }
++
++      *val = FIELD_GET(MDIO_DATA_MASK, data);
++      return MDIO_RD_DONE(data) ? 0 : -EIO;
++}
++
++/* negative return value indicates error */
++static int brcm_pcie_mdio_write(void __iomem *base, u8 port,
++                              u8 regad, u16 wrdata)
++{
++      int tries;
++      u32 data;
++
++      writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
++                 base + PCIE_RC_DL_MDIO_ADDR);
++      readl(base + PCIE_RC_DL_MDIO_ADDR);
++      writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA);
++
++      data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++      for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
++              udelay(10);
++              data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++      }
++
++      return MDIO_WT_DONE(data) ? 0 : -EIO;
++}
++
++/*
++ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
++ * return value indicates error.
++ */
++static int brcm_pcie_set_ssc(struct brcm_pcie *pcie)
++{
++      int pll, ssc;
++      int ret;
++      u32 tmp;
++
++      ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET,
++                                 SSC_REGS_ADDR);
++      if (ret < 0)
++              return ret;
++
++      ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0,
++                                SSC_CNTL_OFFSET, &tmp);
++      if (ret < 0)
++              return ret;
++
++      u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_EN_MASK);
++      u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK);
++      ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0,
++                                 SSC_CNTL_OFFSET, tmp);
++      if (ret < 0)
++              return ret;
++
++      usleep_range(1000, 2000);
++      ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0,
++                                SSC_STATUS_OFFSET, &tmp);
++      if (ret < 0)
++              return ret;
++
++      ssc = FIELD_GET(SSC_STATUS_SSC_MASK, tmp);
++      pll = FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp);
++
++      return ssc && pll ? 0 : -EIO;
++}
++
++/* Limits operation to a specific generation (1, 2, or 3) */
++static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen)
++{
++      u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++      u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++
++      lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
++      writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++
++      lnkctl2 = (lnkctl2 & ~0xf) | gen;
++      writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++}
++
++static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
++                                     unsigned int win, u64 cpu_addr,
++                                     u64 pcie_addr, u64 size)
++{
++      u32 cpu_addr_mb_high, limit_addr_mb_high;
++      phys_addr_t cpu_addr_mb, limit_addr_mb;
++      int high_addr_shift;
++      u32 tmp;
++
++      /* Set the base of the pcie_addr window */
++      writel(lower_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_LO(win));
++      writel(upper_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_HI(win));
++
++      /* Write the addr base & limit lower bits (in MBs) */
++      cpu_addr_mb = cpu_addr / SZ_1M;
++      limit_addr_mb = (cpu_addr + size - 1) / SZ_1M;
++
++      tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win));
++      u32p_replace_bits(&tmp, cpu_addr_mb,
++                        PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK);
++      u32p_replace_bits(&tmp, limit_addr_mb,
++                        PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK);
++      writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win));
++
++      /* Write the cpu & limit addr upper bits */
++      high_addr_shift =
++              HWEIGHT32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK);
++
++      cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift;
++      tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_HI(win));
++      u32p_replace_bits(&tmp, cpu_addr_mb_high,
++                        PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK);
++      writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_HI(win));
++
++      limit_addr_mb_high = limit_addr_mb >> high_addr_shift;
++      tmp = readl(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
++      u32p_replace_bits(&tmp, limit_addr_mb_high,
++                        PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK);
++      writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
++}
++
++/* The controller is capable of serving in both RC and EP roles */
++static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
++{
++      void __iomem *base = pcie->base;
++      u32 val = readl(base + PCIE_MISC_PCIE_STATUS);
++
++      return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val);
++}
++
++static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
++{
++      u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS);
++      u32 dla = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val);
++      u32 plu = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val);
++
++      return dla && plu;
++}
++
++/* Configuration space read/write support */
++static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
++{
++      return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
++              | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
++              | (busnr << PCIE_EXT_BUSNUM_SHIFT)
++              | (reg & ~3);
++}
++
++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
++                                      int where)
++{
++      struct brcm_pcie *pcie = bus->sysdata;
++      void __iomem *base = pcie->base;
++      int idx;
++
++      /* Accesses to the RC go right to the RC registers if slot==0 */
++      if (pci_is_root_bus(bus))
++              return PCI_SLOT(devfn) ? NULL : base + where;
++
++      /* For devices, write to the config space index register */
++      idx = brcm_pcie_cfg_index(bus->number, devfn, 0);
++      writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
++      return base + PCIE_EXT_CFG_DATA + where;
++}
++
++static struct pci_ops brcm_pcie_ops = {
++      .map_bus = brcm_pcie_map_conf,
++      .read = pci_generic_config_read,
++      .write = pci_generic_config_write,
++};
++
++static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
++{
++      u32 tmp;
++
++      tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
++      u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK);
++      writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
++}
++
++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val)
++{
++      u32 tmp;
++
++      tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
++      u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK);
++      writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
++}
++
++static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
++                                                      u64 *rc_bar2_size,
++                                                      u64 *rc_bar2_offset)
++{
++      struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
++      struct device *dev = pcie->dev;
++      struct resource_entry *entry;
++
++      entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
++      if (!entry)
++              return -ENODEV;
++
++
++      /*
++       * The controller expects the inbound window offset to be calculated as
++       * the difference between PCIe's address space and CPU's. The offset
++       * provided by the firmware is calculated the opposite way, so we
++       * negate it.
++       */
++      *rc_bar2_offset = -entry->offset;
++      *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start);
++
++      /*
++       * We validate the inbound memory view even though we should trust
++       * whatever the device-tree provides. This is because of an HW issue on
++       * early Raspberry Pi 4's revisions (bcm2711). It turns out its
++       * firmware has to dynamically edit dma-ranges due to a bug on the
++       * PCIe controller integration, which prohibits any access above the
++       * lower 3GB of memory. Given this, we decided to keep the dma-ranges
++       * in check, avoiding hard to debug device-tree related issues in the
++       * future:
++       *
++       * The PCIe host controller by design must set the inbound viewport to
++       * be a contiguous arrangement of all of the system's memory.  In
++       * addition, its size mut be a power of two.  To further complicate
++       * matters, the viewport must start on a pcie-address that is aligned
++       * on a multiple of its size.  If a portion of the viewport does not
++       * represent system memory -- e.g. 3GB of memory requires a 4GB
++       * viewport -- we can map the outbound memory in or after 3GB and even
++       * though the viewport will overlap the outbound memory the controller
++       * will know to send outbound memory downstream and everything else
++       * upstream.
++       *
++       * For example:
++       *
++       * - The best-case scenario, memory up to 3GB, is to place the inbound
++       *   region in the first 4GB of pcie-space, as some legacy devices can
++       *   only address 32bits. We would also like to put the MSI under 4GB
++       *   as well, since some devices require a 32bit MSI target address.
++       *
++       * - If the system memory is 4GB or larger we cannot start the inbound
++       *   region at location 0 (since we have to allow some space for
++       *   outbound memory @ 3GB). So instead it will  start at the 1x
++       *   multiple of its size
++       */
++      if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
++          (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
++              dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
++                      *rc_bar2_size, *rc_bar2_offset);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static int brcm_pcie_setup(struct brcm_pcie *pcie)
++{
++      struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
++      u64 rc_bar2_offset, rc_bar2_size;
++      void __iomem *base = pcie->base;
++      struct device *dev = pcie->dev;
++      struct resource_entry *entry;
++      unsigned int scb_size_val;
++      bool ssc_good = false;
++      struct resource *res;
++      int num_out_wins = 0;
++      u16 nlw, cls, lnksta;
++      int i, ret;
++      u32 tmp;
++
++      /* Reset the bridge */
++      brcm_pcie_bridge_sw_init_set(pcie, 1);
++
++      usleep_range(100, 200);
++
++      /* Take the bridge out of reset */
++      brcm_pcie_bridge_sw_init_set(pcie, 0);
++
++      tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++      tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK;
++      writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++      /* Wait for SerDes to be stable */
++      usleep_range(100, 200);
++
++      /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
++      u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
++      u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
++      u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128,
++                        PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
++      writel(tmp, base + PCIE_MISC_MISC_CTRL);
++
++      ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
++                                                  &rc_bar2_offset);
++      if (ret)
++              return ret;
++
++      tmp = lower_32_bits(rc_bar2_offset);
++      u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
++                        PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK);
++      writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
++      writel(upper_32_bits(rc_bar2_offset),
++             base + PCIE_MISC_RC_BAR2_CONFIG_HI);
++
++      scb_size_val = rc_bar2_size ?
++                     ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
++      tmp = readl(base + PCIE_MISC_MISC_CTRL);
++      u32p_replace_bits(&tmp, scb_size_val,
++                        PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
++      writel(tmp, base + PCIE_MISC_MISC_CTRL);
++
++      /* disable the PCIe->GISB memory window (RC_BAR1) */
++      tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO);
++      tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK;
++      writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO);
++
++      /* disable the PCIe->SCB memory window (RC_BAR3) */
++      tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO);
++      tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;
++      writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO);
++
++      /* Mask all interrupts since we are not handling any yet */
++      writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET);
++
++      /* clear any interrupts we find on boot */
++      writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR);
++
++      if (pcie->gen)
++              brcm_pcie_set_gen(pcie, pcie->gen);
++
++      /* Unassert the fundamental reset */
++      brcm_pcie_perst_set(pcie, 0);
++
++      /*
++       * Give the RC/EP time to wake up, before trying to configure RC.
++       * Intermittently check status for link-up, up to a total of 100ms.
++       */
++      for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5)
++              msleep(5);
++
++      if (!brcm_pcie_link_up(pcie)) {
++              dev_err(dev, "link down\n");
++              return -ENODEV;
++      }
++
++      if (!brcm_pcie_rc_mode(pcie)) {
++              dev_err(dev, "PCIe misconfigured; is in EP mode\n");
++              return -EINVAL;
++      }
++
++      resource_list_for_each_entry(entry, &bridge->windows) {
++              res = entry->res;
++
++              if (resource_type(res) != IORESOURCE_MEM)
++                      continue;
++
++              if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
++                      dev_err(pcie->dev, "too many outbound wins\n");
++                      return -EINVAL;
++              }
++
++              brcm_pcie_set_outbound_win(pcie, num_out_wins, res->start,
++                                         res->start - entry->offset,
++                                         resource_size(res));
++              num_out_wins++;
++      }
++
++      /*
++       * For config space accesses on the RC, show the right class for
++       * a PCIe-PCIe bridge (the default setting is to be EP mode).
++       */
++      tmp = readl(base + PCIE_RC_CFG_PRIV1_ID_VAL3);
++      u32p_replace_bits(&tmp, 0x060400,
++                        PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK);
++      writel(tmp, base + PCIE_RC_CFG_PRIV1_ID_VAL3);
++
++      if (pcie->ssc) {
++              ret = brcm_pcie_set_ssc(pcie);
++              if (ret == 0)
++                      ssc_good = true;
++              else
++                      dev_err(dev, "failed attempt to enter ssc mode\n");
++      }
++
++      lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
++      cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta);
++      nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
++      dev_info(dev, "link up, %s x%u %s\n",
++               PCIE_SPEED2STR(cls + PCI_SPEED_133MHz_PCIX_533),
++               nlw, ssc_good ? "(SSC)" : "(!SSC)");
++
++      /* PCIe->SCB endian mode for BAR */
++      tmp = readl(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
++      u32p_replace_bits(&tmp, PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN,
++              PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
++      writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
++
++      /*
++       * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
++       * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
++       */
++      tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++      tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
++      writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++
++      return 0;
++}
++
++/* L23 is a low-power PCIe link state */
++static void brcm_pcie_enter_l23(struct brcm_pcie *pcie)
++{
++      void __iomem *base = pcie->base;
++      int l23, i;
++      u32 tmp;
++
++      /* Assert request for L23 */
++      tmp = readl(base + PCIE_MISC_PCIE_CTRL);
++      u32p_replace_bits(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK);
++      writel(tmp, base + PCIE_MISC_PCIE_CTRL);
++
++      /* Wait up to 36 msec for L23 */
++      tmp = readl(base + PCIE_MISC_PCIE_STATUS);
++      l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp);
++      for (i = 0; i < 15 && !l23; i++) {
++              usleep_range(2000, 2400);
++              tmp = readl(base + PCIE_MISC_PCIE_STATUS);
++              l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK,
++                              tmp);
++      }
++
++      if (!l23)
++              dev_err(pcie->dev, "failed to enter low-power link state\n");
++}
++
++static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
++{
++      void __iomem *base = pcie->base;
++      int tmp;
++
++      if (brcm_pcie_link_up(pcie))
++              brcm_pcie_enter_l23(pcie);
++      /* Assert fundamental reset */
++      brcm_pcie_perst_set(pcie, 1);
++
++      /* Deassert request for L23 in case it was asserted */
++      tmp = readl(base + PCIE_MISC_PCIE_CTRL);
++      u32p_replace_bits(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK);
++      writel(tmp, base + PCIE_MISC_PCIE_CTRL);
++
++      /* Turn off SerDes */
++      tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++      u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
++      writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++
++      /* Shutdown PCIe bridge */
++      brcm_pcie_bridge_sw_init_set(pcie, 1);
++}
++
++static void __brcm_pcie_remove(struct brcm_pcie *pcie)
++{
++      brcm_pcie_turn_off(pcie);
++      clk_disable_unprepare(pcie->clk);
++      clk_put(pcie->clk);
++}
++
++static int brcm_pcie_remove(struct platform_device *pdev)
++{
++      struct brcm_pcie *pcie = platform_get_drvdata(pdev);
++
++      pci_stop_root_bus(pcie->root_bus);
++      pci_remove_root_bus(pcie->root_bus);
++      __brcm_pcie_remove(pcie);
++
++      return 0;
++}
++
++static int brcm_pcie_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct pci_host_bridge *bridge;
++      struct brcm_pcie *pcie;
++      struct pci_bus *child;
++      struct resource *res;
++      int ret;
++
++      bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
++      if (!bridge)
++              return -ENOMEM;
++
++      pcie = pci_host_bridge_priv(bridge);
++      pcie->dev = &pdev->dev;
++      pcie->np = np;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pcie->base = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(pcie->base))
++              return PTR_ERR(pcie->base);
++
++      pcie->clk = devm_clk_get_optional(&pdev->dev, "sw_pcie");
++      if (IS_ERR(pcie->clk))
++              return PTR_ERR(pcie->clk);
++
++      ret = of_pci_get_max_link_speed(np);
++      pcie->gen = (ret < 0) ? 0 : ret;
++
++      pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
++
++      ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows,
++                                            &bridge->dma_ranges, NULL);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(pcie->clk);
++      if (ret) {
++              dev_err(&pdev->dev, "could not enable clock\n");
++              return ret;
++      }
++
++      ret = brcm_pcie_setup(pcie);
++      if (ret)
++              goto fail;
++
++      bridge->dev.parent = &pdev->dev;
++      bridge->busnr = 0;
++      bridge->ops = &brcm_pcie_ops;
++      bridge->sysdata = pcie;
++      bridge->map_irq = of_irq_parse_and_map_pci;
++      bridge->swizzle_irq = pci_common_swizzle;
++
++      ret = pci_scan_root_bus_bridge(bridge);
++      if (ret < 0) {
++              dev_err(pcie->dev, "Scanning root bridge failed\n");
++              goto fail;
++      }
++
++      pci_assign_unassigned_bus_resources(bridge->bus);
++      list_for_each_entry(child, &bridge->bus->children, node)
++              pcie_bus_configure_settings(child);
++      pci_bus_add_devices(bridge->bus);
++      platform_set_drvdata(pdev, pcie);
++      pcie->root_bus = bridge->bus;
++
++      return 0;
++fail:
++      __brcm_pcie_remove(pcie);
++      return ret;
++}
++
++static const struct of_device_id brcm_pcie_match[] = {
++      { .compatible = "brcm,bcm2711-pcie" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, brcm_pcie_match);
++
++static struct platform_driver brcm_pcie_driver = {
++      .probe = brcm_pcie_probe,
++      .remove = brcm_pcie_remove,
++      .driver = {
++              .name = "brcm-pcie",
++              .of_match_table = brcm_pcie_match,
++      },
++};
++module_platform_driver(brcm_pcie_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
++MODULE_AUTHOR("Broadcom");
diff --git a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch
new file mode 100644 (file)
index 0000000..a27259b
--- /dev/null
@@ -0,0 +1,383 @@
+From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001
+From: Jim Quinlan <james.quinlan@broadcom.com>
+Date: Mon, 16 Dec 2019 12:01:10 +0100
+Subject: [PATCH] PCI: brcmstb: Add MSI support
+
+commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream.
+
+This adds MSI support to the Broadcom STB PCIe host controller. The MSI
+controller is physically located within the PCIe block, however, there
+is no reason why the MSI controller could not be moved elsewhere in the
+future. MSIX is not supported by the HW.
+
+Since the internal Brcmstb MSI controller is intertwined with the PCIe
+controller, it is not its own platform device but rather part of the
+PCIe platform device.
+
+Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
+Co-developed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+---
+ drivers/pci/controller/Kconfig        |   1 +
+ drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++-
+ 2 files changed, 262 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -285,6 +285,7 @@ config PCIE_BRCMSTB
+       tristate "Broadcom Brcmstb PCIe host controller"
+       depends on ARCH_BCM2835 || COMPILE_TEST
+       depends on OF
++      depends on PCI_MSI_IRQ_DOMAIN
+       help
+         Say Y here to enable PCIe host controller support for
+         Broadcom STB based SoCs, like the Raspberry Pi 4.
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -2,6 +2,7 @@
+ /* Copyright (C) 2009 - 2019 Broadcom */
+ #include <linux/bitfield.h>
++#include <linux/bitops.h>
+ #include <linux/clk.h>
+ #include <linux/compiler.h>
+ #include <linux/delay.h>
+@@ -9,11 +10,13 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/ioport.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/log2.h>
+ #include <linux/module.h>
++#include <linux/msi.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_pci.h>
+@@ -67,6 +70,12 @@
+ #define PCIE_MISC_RC_BAR3_CONFIG_LO                   0x403c
+ #define  PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK                0x1f
++#define PCIE_MISC_MSI_BAR_CONFIG_LO                   0x4044
++#define PCIE_MISC_MSI_BAR_CONFIG_HI                   0x4048
++
++#define PCIE_MISC_MSI_DATA_CONFIG                     0x404c
++#define  PCIE_MISC_MSI_DATA_CONFIG_VAL                        0xffe06540
++
+ #define PCIE_MISC_PCIE_CTRL                           0x4064
+ #define  PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK    0x1
+@@ -114,6 +123,11 @@
+ /* PCIe parameters */
+ #define BRCM_NUM_PCIE_OUT_WINS                0x4
++#define BRCM_INT_PCI_MSI_NR           32
++
++/* MSI target adresses */
++#define BRCM_MSI_TARGET_ADDR_LT_4GB   0x0fffffffcULL
++#define BRCM_MSI_TARGET_ADDR_GT_4GB   0xffffffffcULL
+ /* MDIO registers */
+ #define MDIO_PORT0                    0x0
+@@ -135,6 +149,19 @@
+ #define SSC_STATUS_SSC_MASK           0x400
+ #define SSC_STATUS_PLL_LOCK_MASK      0x800
++struct brcm_msi {
++      struct device           *dev;
++      void __iomem            *base;
++      struct device_node      *np;
++      struct irq_domain       *msi_domain;
++      struct irq_domain       *inner_domain;
++      struct mutex            lock; /* guards the alloc/free operations */
++      u64                     target_addr;
++      int                     irq;
++      /* used indicates which MSI interrupts have been alloc'd */
++      unsigned long           used;
++};
++
+ /* Internal PCIe Host Controller Information.*/
+ struct brcm_pcie {
+       struct device           *dev;
+@@ -144,6 +171,8 @@ struct brcm_pcie {
+       struct device_node      *np;
+       bool                    ssc;
+       int                     gen;
++      u64                     msi_target_addr;
++      struct brcm_msi         *msi;
+ };
+ /*
+@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s
+       writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
+ }
++static struct irq_chip brcm_msi_irq_chip = {
++      .name            = "BRCM STB PCIe MSI",
++      .irq_ack         = irq_chip_ack_parent,
++      .irq_mask        = pci_msi_mask_irq,
++      .irq_unmask      = pci_msi_unmask_irq,
++};
++
++static struct msi_domain_info brcm_msi_domain_info = {
++      /* Multi MSI is supported by the controller, but not by this driver */
++      .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
++      .chip   = &brcm_msi_irq_chip,
++};
++
++static void brcm_pcie_msi_isr(struct irq_desc *desc)
++{
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      unsigned long status, virq;
++      struct brcm_msi *msi;
++      struct device *dev;
++      u32 bit;
++
++      chained_irq_enter(chip, desc);
++      msi = irq_desc_get_handler_data(desc);
++      dev = msi->dev;
++
++      status = readl(msi->base + PCIE_MSI_INTR2_STATUS);
++      for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
++              virq = irq_find_mapping(msi->inner_domain, bit);
++              if (virq)
++                      generic_handle_irq(virq);
++              else
++                      dev_dbg(dev, "unexpected MSI\n");
++      }
++
++      chained_irq_exit(chip, desc);
++}
++
++static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
++{
++      struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
++
++      msg->address_lo = lower_32_bits(msi->target_addr);
++      msg->address_hi = upper_32_bits(msi->target_addr);
++      msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq;
++}
++
++static int brcm_msi_set_affinity(struct irq_data *irq_data,
++                               const struct cpumask *mask, bool force)
++{
++      return -EINVAL;
++}
++
++static void brcm_msi_ack_irq(struct irq_data *data)
++{
++      struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
++
++      writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR);
++}
++
++
++static struct irq_chip brcm_msi_bottom_irq_chip = {
++      .name                   = "BRCM STB MSI",
++      .irq_compose_msi_msg    = brcm_msi_compose_msi_msg,
++      .irq_set_affinity       = brcm_msi_set_affinity,
++      .irq_ack                = brcm_msi_ack_irq,
++};
++
++static int brcm_msi_alloc(struct brcm_msi *msi)
++{
++      int hwirq;
++
++      mutex_lock(&msi->lock);
++      hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0);
++      mutex_unlock(&msi->lock);
++
++      return hwirq;
++}
++
++static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
++{
++      mutex_lock(&msi->lock);
++      bitmap_release_region(&msi->used, hwirq, 0);
++      mutex_unlock(&msi->lock);
++}
++
++static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
++                               unsigned int nr_irqs, void *args)
++{
++      struct brcm_msi *msi = domain->host_data;
++      int hwirq;
++
++      hwirq = brcm_msi_alloc(msi);
++
++      if (hwirq < 0)
++              return hwirq;
++
++      irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
++                          &brcm_msi_bottom_irq_chip, domain->host_data,
++                          handle_edge_irq, NULL, NULL);
++      return 0;
++}
++
++static void brcm_irq_domain_free(struct irq_domain *domain,
++                               unsigned int virq, unsigned int nr_irqs)
++{
++      struct irq_data *d = irq_domain_get_irq_data(domain, virq);
++      struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
++
++      brcm_msi_free(msi, d->hwirq);
++}
++
++static const struct irq_domain_ops msi_domain_ops = {
++      .alloc  = brcm_irq_domain_alloc,
++      .free   = brcm_irq_domain_free,
++};
++
++static int brcm_allocate_domains(struct brcm_msi *msi)
++{
++      struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);
++      struct device *dev = msi->dev;
++
++      msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
++                                                &msi_domain_ops, msi);
++      if (!msi->inner_domain) {
++              dev_err(dev, "failed to create IRQ domain\n");
++              return -ENOMEM;
++      }
++
++      msi->msi_domain = pci_msi_create_irq_domain(fwnode,
++                                                  &brcm_msi_domain_info,
++                                                  msi->inner_domain);
++      if (!msi->msi_domain) {
++              dev_err(dev, "failed to create MSI domain\n");
++              irq_domain_remove(msi->inner_domain);
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static void brcm_free_domains(struct brcm_msi *msi)
++{
++      irq_domain_remove(msi->msi_domain);
++      irq_domain_remove(msi->inner_domain);
++}
++
++static void brcm_msi_remove(struct brcm_pcie *pcie)
++{
++      struct brcm_msi *msi = pcie->msi;
++
++      if (!msi)
++              return;
++      irq_set_chained_handler(msi->irq, NULL);
++      irq_set_handler_data(msi->irq, NULL);
++      brcm_free_domains(msi);
++}
++
++static void brcm_msi_set_regs(struct brcm_msi *msi)
++{
++      writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR);
++
++      /*
++       * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
++       * enable, which we set to 1.
++       */
++      writel(lower_32_bits(msi->target_addr) | 0x1,
++             msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
++      writel(upper_32_bits(msi->target_addr),
++             msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
++
++      writel(PCIE_MISC_MSI_DATA_CONFIG_VAL,
++             msi->base + PCIE_MISC_MSI_DATA_CONFIG);
++}
++
++static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
++{
++      struct brcm_msi *msi;
++      int irq, ret;
++      struct device *dev = pcie->dev;
++
++      irq = irq_of_parse_and_map(dev->of_node, 1);
++      if (irq <= 0) {
++              dev_err(dev, "cannot map MSI interrupt\n");
++              return -ENODEV;
++      }
++
++      msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
++      if (!msi)
++              return -ENOMEM;
++
++      mutex_init(&msi->lock);
++      msi->dev = dev;
++      msi->base = pcie->base;
++      msi->np = pcie->np;
++      msi->target_addr = pcie->msi_target_addr;
++      msi->irq = irq;
++
++      ret = brcm_allocate_domains(msi);
++      if (ret)
++              return ret;
++
++      irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
++
++      brcm_msi_set_regs(msi);
++      pcie->msi = msi;
++
++      return 0;
++}
++
+ /* The controller is capable of serving in both RC and EP roles */
+ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
+ {
+@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p
+                         PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
+       writel(tmp, base + PCIE_MISC_MISC_CTRL);
++      /*
++       * We ideally want the MSI target address to be located in the 32bit
++       * addressable memory area. Some devices might depend on it. This is
++       * possible either when the inbound window is located above the lower
++       * 4GB or when the inbound area is smaller than 4GB (taking into
++       * account the rounding-up we're forced to perform).
++       */
++      if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G)
++              pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
++      else
++              pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
++
+       /* disable the PCIe->GISB memory window (RC_BAR1) */
+       tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO);
+       tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK;
+@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br
+ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
+ {
++      brcm_msi_remove(pcie);
+       brcm_pcie_turn_off(pcie);
+       clk_disable_unprepare(pcie->clk);
+       clk_put(pcie->clk);
+@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf
+ static int brcm_pcie_probe(struct platform_device *pdev)
+ {
+-      struct device_node *np = pdev->dev.of_node;
++      struct device_node *np = pdev->dev.of_node, *msi_np;
+       struct pci_host_bridge *bridge;
+       struct brcm_pcie *pcie;
+       struct pci_bus *child;
+@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo
+       if (ret)
+               goto fail;
++      msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
++      if (pci_msi_enabled() && msi_np == pcie->np) {
++              ret = brcm_pcie_enable_msi(pcie);
++              if (ret) {
++                      dev_err(pcie->dev, "probe of internal MSI failed");
++                      goto fail;
++              }
++      }
++
+       bridge->dev.parent = &pdev->dev;
+       bridge->busnr = 0;
+       bridge->ops = &brcm_pcie_ops;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch b/target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch
new file mode 100644 (file)
index 0000000..6bb45cc
--- /dev/null
@@ -0,0 +1,38 @@
+From 39192141aa16809323c24d8910e3a63488f7f55d Mon Sep 17 00:00:00 2001
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+Date: Thu, 27 Feb 2020 12:51:46 +0100
+Subject: [PATCH] PCI: brcmstb: Fix build on 32bit ARM platforms with
+ older compilers
+
+commit 73a7a271b3eee7b83f29b13866163776f1cbef89 upstream.
+
+Some older compilers have no implementation for the helper for 64-bit
+unsigned division/modulo, so linking pcie-brcmstb driver causes the
+"undefined reference to `__aeabi_uldivmod'" error.
+
+*rc_bar2_size is always a power of two, because it is calculated as:
+"1ULL << fls64(entry->res->end - entry->res->start)", so the modulo
+operation in the subsequent check can be replaced by a simple logical
+AND with a proper mask.
+
+Link: https://lore.kernel.org/r/20200227115146.24515-1-m.szyprowski@samsung.com
+Fixes: c0452137034b ("PCI: brcmstb: Add Broadcom STB PCIe host controller driver")
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/controller/pcie-brcmstb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_
+        *   outbound memory @ 3GB). So instead it will  start at the 1x
+        *   multiple of its size
+        */
+-      if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
++      if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) ||
+           (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
+               dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
+                       *rc_bar2_size, *rc_bar2_offset);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch b/target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch
new file mode 100644 (file)
index 0000000..729d6e6
--- /dev/null
@@ -0,0 +1,75 @@
+From 5e9b9f246802f492e7740ab2589aa8c81df5ef20 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 2 Mar 2020 15:05:25 +0000
+Subject: [PATCH] bcm2711-rpi.dtsi: Use upstream pcie node
+
+Now that the upstream bcm2711 DT has a pcie DT node there's no need to
+define one downstream.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts |  2 +-
+ arch/arm/boot/dts/bcm2711-rpi.dtsi    | 41 ---------------------------
+ 2 files changed, 1 insertion(+), 42 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -163,7 +163,7 @@
+               i2c6 = &i2c6;
+               /delete-property/ ethernet;
+               /delete-property/ intc;
+-              pcie0 = &pcie_0;
++              pcie0 = &pcie0;
+       };
+       /delete-node/ wifi-pwrseq;
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -66,47 +66,6 @@
+                <0x0 0x00000000  0x0 0x00000000  0xfc000000>;
+       dma-ranges = <0x0 0x00000000  0x0 0x00000000  0xfc000000>;
+-      pcie_0: pcie@7d500000 {
+-              reg = <0x0 0x7d500000 0x9310>,
+-                    <0x0 0x7e00f300 0x20>;
+-              msi-controller;
+-              msi-parent = <&pcie_0>;
+-              #address-cells = <3>;
+-              #interrupt-cells = <1>;
+-              #size-cells = <2>;
+-              bus-range = <0x0 0x01>;
+-              compatible = "brcm,bcm2711b0-pcie", // Safe value
+-                           "brcm,bcm2711-pcie",
+-                           "brcm,pci-plat-dev";
+-              max-link-speed = <2>;
+-              tot-num-pcie = <1>;
+-              linux,pci-domain = <0>;
+-              interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+-                           <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+-              interrupt-names = "pcie", "msi";
+-              interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+-              interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
+-                                      IRQ_TYPE_LEVEL_HIGH
+-                               0 0 0 2 &gicv2 GIC_SPI 144
+-                                      IRQ_TYPE_LEVEL_HIGH
+-                               0 0 0 3 &gicv2 GIC_SPI 145
+-                                      IRQ_TYPE_LEVEL_HIGH
+-                               0 0 0 4 &gicv2 GIC_SPI 146
+-                                      IRQ_TYPE_LEVEL_HIGH>;
+-
+-              /* Map outbound accesses from scb:0x6_00000000-03ffffff
+-               * to pci:0x0_f8000000-fbffffff
+-               */
+-              ranges = <0x02000000 0x0 0xf8000000  0x6 0x00000000
+-                        0x0 0x04000000>;
+-              /* Map inbound accesses from pci:0x0_00000000..ffffffff
+-               * to scb:0x0_00000000-ffffffff
+-               */
+-              dma-ranges = <0x02000000 0x0 0x00000000  0x0 0x00000000
+-                            0x1 0x00000000>;
+-              status = "okay";
+-      };
+-
+       dma40: dma@7e007b00 {
+               compatible = "brcm,bcm2711-dma";
+               reg = <0x0 0x7e007b00 0x400>;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch b/target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch
new file mode 100644 (file)
index 0000000..16eaedd
--- /dev/null
@@ -0,0 +1,156 @@
+From a3ceeebaaa66e6786490e850b5019808da3785c0 Mon Sep 17 00:00:00 2001
+From: Andrey Konovalov <andrey.konovalov@linaro.org>
+Date: Mon, 20 Jan 2020 05:15:57 -0300
+Subject: [PATCH] media: dt-bindings: media: i2c: Add IMX219 CMOS
+ sensor binding
+
+Commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream.
+(Currently on linux-media/master, queued for 5.7)
+
+Add YAML device tree binding for IMX219 CMOS image sensor, and
+the relevant MAINTAINERS entries.
+
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+---
+ .../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++
+ MAINTAINERS                                   |   8 ++
+ 2 files changed, 122 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml
+@@ -0,0 +1,114 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/media/i2c/imx219.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
++
++maintainers:
++  - Dave Stevenson <dave.stevenson@raspberrypi.com>
++
++description: |-
++  The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor
++  with an active array size of 3280H x 2464V. It is programmable through
++  I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet.
++  Image data is sent through MIPI CSI-2, which is configured as either 2 or
++  4 data lanes.
++
++properties:
++  compatible:
++    const: sony,imx219
++
++  reg:
++    description: I2C device address
++    maxItems: 1
++
++  clocks:
++    maxItems: 1
++
++  VDIG-supply:
++    description:
++      Digital I/O voltage supply, 1.8 volts
++
++  VANA-supply:
++    description:
++      Analog voltage supply, 2.8 volts
++
++  VDDL-supply:
++    description:
++      Digital core voltage supply, 1.2 volts
++
++  reset-gpios:
++    description: |-
++      Reference to the GPIO connected to the xclr pin, if any.
++      Must be released (set high) after all supplies are applied.
++
++  # See ../video-interfaces.txt for more details
++  port:
++    type: object
++    properties:
++      endpoint:
++        type: object
++        properties:
++          data-lanes:
++            description: |-
++              The sensor supports either two-lane, or four-lane operation.
++              If this property is omitted four-lane operation is assumed.
++              For two-lane operation the property must be set to <1 2>.
++            items:
++              - const: 1
++              - const: 2
++
++          clock-noncontinuous:
++            type: boolean
++            description: |-
++              MIPI CSI-2 clock is non-continuous if this property is present,
++              otherwise it's continuous.
++
++          link-frequencies:
++            allOf:
++              - $ref: /schemas/types.yaml#/definitions/uint64-array
++            description:
++              Allowed data bus frequencies.
++
++        required:
++          - link-frequencies
++
++required:
++  - compatible
++  - reg
++  - clocks
++  - VANA-supply
++  - VDIG-supply
++  - VDDL-supply
++  - port
++
++additionalProperties: false
++
++examples:
++  - |
++    i2c0 {
++        #address-cells = <1>;
++        #size-cells = <0>;
++
++        imx219: sensor@10 {
++            compatible = "sony,imx219";
++            reg = <0x10>;
++            clocks = <&imx219_clk>;
++            VANA-supply = <&imx219_vana>;   /* 2.8v */
++            VDIG-supply = <&imx219_vdig>;   /* 1.8v */
++            VDDL-supply = <&imx219_vddl>;   /* 1.2v */
++
++            port {
++                imx219_0: endpoint {
++                    remote-endpoint = <&csi1_ep>;
++                    data-lanes = <1 2>;
++                    clock-noncontinuous;
++                    link-frequencies = /bits/ 64 <456000000>;
++                };
++            };
++        };
++    };
++
++...
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -15142,6 +15142,14 @@ S:    Maintained
+ F:    drivers/media/i2c/imx214.c
+ F:    Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
++SONY IMX219 SENSOR DRIVER
++M:    Dave Stevenson <dave.stevenson@raspberrypi.com>
++L:    linux-media@vger.kernel.org
++T:    git git://linuxtv.org/media_tree.git
++S:    Maintained
++F:    drivers/media/i2c/imx219.c
++F:    Documentation/devicetree/bindings/media/i2c/imx219.yaml
++
+ SONY IMX258 SENSOR DRIVER
+ M:    Sakari Ailus <sakari.ailus@linux.intel.com>
+ L:    linux-media@vger.kernel.org
similarity index 64%
rename from target/linux/bcm27xx/patches-5.4/950-0312-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch
rename to target/linux/bcm27xx/patches-5.4/950-0464-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch
index 0880d419c769380c72067cfcd895cc56c76639c3..4ca345f2ad597cab0f72b1cd2a181ef899ee45bb 100644 (file)
@@ -1,21 +1,28 @@
-From 8436bbdd722445870c514d889eb082155f88dde1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 28 Aug 2019 13:34:49 +0100
+From 5cd8c4efeb46ce1ef370dd3012a7951ba430b58f Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 20 Jan 2020 05:15:58 -0300
 Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor
 
+Commit 1283b3b8f82b9004fbb94398cade5c8e797a2c8d upstream.
+(Currently on linux-media/master, queued for 5.7)
+
 Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
 Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
 currently only supports 2 lanes.
 8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
 @ 30fps are currently supported.
 
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+[Sakari Ailus: make imx219_check_hwcfg static]
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
 ---
  drivers/media/i2c/Kconfig  |   11 +
  drivers/media/i2c/Makefile |    1 +
- drivers/media/i2c/imx219.c | 1093 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 1105 insertions(+)
+ drivers/media/i2c/imx219.c | 1312 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1324 insertions(+)
  create mode 100644 drivers/media/i2c/imx219.c
 
 --- a/drivers/media/i2c/Kconfig
@@ -27,7 +34,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +config VIDEO_IMX219
 +      tristate "Sony IMX219 sensor support"
 +      depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+      depends on MEDIA_CAMERA_SUPPORT
++      select V4L2_FWNODE
 +      help
 +        This is a Video4Linux2 sensor driver for the Sony
 +        IMX219 camera.
@@ -40,7 +47,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
 --- a/drivers/media/i2c/Makefile
 +++ b/drivers/media/i2c/Makefile
-@@ -110,6 +110,7 @@ obj-$(CONFIG_VIDEO_ML86V7667)      += ml86v76
+@@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_ML86V7667)      += ml86v76
  obj-$(CONFIG_VIDEO_OV2659)    += ov2659.o
  obj-$(CONFIG_VIDEO_TC358743)  += tc358743.o
  obj-$(CONFIG_VIDEO_IMX214)    += imx214.o
@@ -50,7 +57,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
  obj-$(CONFIG_VIDEO_IMX319)    += imx319.o
 --- /dev/null
 +++ b/drivers/media/i2c/imx219.c
-@@ -0,0 +1,1093 @@
+@@ -0,0 +1,1312 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * A V4L2 driver for Sony IMX219 cameras.
@@ -59,9 +66,11 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 + * Based on Sony imx258 camera driver
 + * Copyright (C) 2018 Intel Corporation
 + *
-+ * DT / fwnode changes, and regulator / GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
++ * Copyright 2018 Qtechnology A/S
++ *
++ * Flip handling taken from the Sony IMX319 driver.
++ * Copyright (C) 2018 Intel Corporation
 + *
 + */
 +
@@ -76,6 +85,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#include <linux/regulator/consumer.h>
 +#include <media/v4l2-ctrls.h>
 +#include <media/v4l2-device.h>
++#include <media/v4l2-event.h>
 +#include <media/v4l2-fwnode.h>
 +#include <media/v4l2-mediabus.h>
 +#include <asm/unaligned.h>
@@ -91,6 +101,14 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#define IMX219_REG_CHIP_ID            0x0000
 +#define IMX219_CHIP_ID                        0x0219
 +
++/* External clock frequency is 24.0M */
++#define IMX219_XCLK_FREQ              24000000
++
++/* Pixel rate is fixed at 182.4M for all the modes */
++#define IMX219_PIXEL_RATE             182400000
++
++#define IMX219_DEFAULT_LINK_FREQ      456000000
++
 +/* V_TIMING internal */
 +#define IMX219_REG_VTS                        0x0160
 +#define IMX219_VTS_15FPS              0x0dc6
@@ -98,6 +116,8 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#define IMX219_VTS_30FPS_BINNED               0x06e3
 +#define IMX219_VTS_MAX                        0xffff
 +
++#define IMX219_VBLANK_MIN             4
++
 +/*Frame Length Line*/
 +#define IMX219_FLL_MIN                        0x08a6
 +#define IMX219_FLL_MAX                        0xffff
@@ -105,7 +125,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#define IMX219_FLL_DEFAULT            0x0c98
 +
 +/* HBLANK control - read only */
-+#define IMX219_PPL_DEFAULT            5352
++#define IMX219_PPL_DEFAULT            3448
 +
 +/* Exposure control */
 +#define IMX219_REG_EXPOSURE           0x015a
@@ -128,6 +148,8 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#define IMX219_DGTL_GAIN_DEFAULT      0x0100
 +#define IMX219_DGTL_GAIN_STEP         1
 +
++#define IMX219_REG_ORIENTATION                0x0172
++
 +/* Test Pattern Control */
 +#define IMX219_REG_TEST_PATTERN               0x0600
 +#define IMX219_TEST_PATTERN_DISABLE   0
@@ -136,25 +158,38 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +#define IMX219_TEST_PATTERN_GREY_COLOR        3
 +#define IMX219_TEST_PATTERN_PN9               4
 +
++/* Test pattern colour components */
++#define IMX219_REG_TESTP_RED          0x0602
++#define IMX219_REG_TESTP_GREENR               0x0604
++#define IMX219_REG_TESTP_BLUE         0x0606
++#define IMX219_REG_TESTP_GREENB               0x0608
++#define IMX219_TESTP_COLOUR_MIN               0
++#define IMX219_TESTP_COLOUR_MAX               0x03ff
++#define IMX219_TESTP_COLOUR_STEP      1
++#define IMX219_TESTP_RED_DEFAULT      IMX219_TESTP_COLOUR_MAX
++#define IMX219_TESTP_GREENR_DEFAULT   0
++#define IMX219_TESTP_BLUE_DEFAULT     0
++#define IMX219_TESTP_GREENB_DEFAULT   0
++
 +struct imx219_reg {
 +      u16 address;
 +      u8 val;
 +};
 +
 +struct imx219_reg_list {
-+      u32 num_of_regs;
++      unsigned int num_of_regs;
 +      const struct imx219_reg *regs;
 +};
 +
 +/* Mode : resolution and related config&values */
 +struct imx219_mode {
 +      /* Frame width */
-+      u32 width;
++      unsigned int width;
 +      /* Frame height */
-+      u32 height;
++      unsigned int height;
 +
 +      /* V-timing */
-+      u32 vts_def;
++      unsigned int vts_def;
 +
 +      /* Default register values */
 +      struct imx219_reg_list reg_list;
@@ -221,8 +256,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      {0x4793, 0x10},
 +      {0x4797, 0x0e},
 +      {0x479b, 0x0e},
-+
-+      {0x0172, 0x03},
 +      {0x0162, 0x0d},
 +      {0x0163, 0x78},
 +};
@@ -269,6 +302,10 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      {0x030b, 0x01},
 +      {0x030c, 0x00},
 +      {0x030d, 0x72},
++      {0x0624, 0x07},
++      {0x0625, 0x80},
++      {0x0626, 0x04},
++      {0x0627, 0x38},
 +      {0x455e, 0x00},
 +      {0x471e, 0x4b},
 +      {0x4767, 0x0f},
@@ -281,13 +318,12 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      {0x4793, 0x10},
 +      {0x4797, 0x0e},
 +      {0x479b, 0x0e},
-+
-+      {0x0172, 0x03},
 +      {0x0162, 0x0d},
 +      {0x0163, 0x78},
 +};
 +
 +static const struct imx219_reg mode_1640_1232_regs[] = {
++      {0x0100, 0x00},
 +      {0x30eb, 0x0c},
 +      {0x30eb, 0x05},
 +      {0x300a, 0xff},
@@ -326,6 +362,10 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      {0x030b, 0x01},
 +      {0x030c, 0x00},
 +      {0x030d, 0x72},
++      {0x0624, 0x06},
++      {0x0625, 0x68},
++      {0x0626, 0x04},
++      {0x0627, 0xd0},
 +      {0x455e, 0x00},
 +      {0x471e, 0x4b},
 +      {0x4767, 0x0f},
@@ -338,8 +378,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      {0x4793, 0x10},
 +      {0x4797, 0x0e},
 +      {0x479b, 0x0e},
-+
-+      {0x0172, 0x03},
 +      {0x0162, 0x0d},
 +      {0x0163, 0x78},
 +};
@@ -370,7 +408,32 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +
 +#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
 +
-+#define IMX219_XCLR_DELAY_MS 10       /* Initialisation delay after XCLR low->high */
++/*
++ * Initialisation delay between XCLR low->high and the moment when the sensor
++ * can start capture (i.e. can leave software stanby) must be not less than:
++ *   t4 + max(t5, t6 + <time to initialize the sensor register over I2C>)
++ * where
++ *   t4 is fixed, and is max 200uS,
++ *   t5 is fixed, and is 6000uS,
++ *   t6 depends on the sensor external clock, and is max 32000 clock periods.
++ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
++ * So for any acceptable external clock t6 is always within the range of
++ * 1185 to 5333 uS, and is always less than t5.
++ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
++ * initialize the sensor over I2C, and then exit the software standby.
++ *
++ * This start-up time can be optimized a bit more, if we start the writes
++ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
++ * initialization over I2C may complete before (t4+t5) expires, and we must
++ * ensure that capture is not started before (t4+t5).
++ *
++ * This delay doesn't account for the power supply startup time. If needed,
++ * this should be taken care of via the regulator framework. E.g. in the
++ * case of DT for regulator-fixed one should define the startup-delay-us
++ * property.
++ */
++#define IMX219_XCLR_MIN_DELAY_US      6200
++#define IMX219_XCLR_DELAY_RANGE_US    1000
 +
 +/* Mode configs */
 +static const struct imx219_mode supported_modes[] = {
@@ -410,17 +473,20 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      struct v4l2_subdev sd;
 +      struct media_pad pad;
 +
-+      struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
 +      struct clk *xclk; /* system clock to IMX219 */
 +      u32 xclk_freq;
 +
-+      struct gpio_desc *xclr_gpio;
++      struct gpio_desc *reset_gpio;
 +      struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
 +
 +      struct v4l2_ctrl_handler ctrl_handler;
 +      /* V4L2 Controls */
 +      struct v4l2_ctrl *pixel_rate;
 +      struct v4l2_ctrl *exposure;
++      struct v4l2_ctrl *vflip;
++      struct v4l2_ctrl *hflip;
++      struct v4l2_ctrl *vblank;
++      struct v4l2_ctrl *hblank;
 +
 +      /* Current mode */
 +      const struct imx219_mode *mode;
@@ -431,7 +497,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +       */
 +      struct mutex mutex;
 +
-+      int power_count;
 +      /* Streaming on/off */
 +      bool streaming;
 +};
@@ -513,101 +578,38 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      return 0;
 +}
 +
-+/* Power/clock management functions */
-+static void imx219_power(struct imx219 *imx219, bool enable)
-+{
-+      gpiod_set_value_cansleep(imx219->xclr_gpio, enable ? 1 : 0);
-+}
-+
-+static int imx219_set_power_on(struct imx219 *imx219)
-+{
-+      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+      int ret;
-+
-+      ret = clk_prepare_enable(imx219->xclk);
-+      if (ret) {
-+              dev_err(&client->dev, "%s: failed to enable clock\n",
-+                      __func__);
-+              return ret;
-+      }
-+
-+      ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
-+                                  imx219->supplies);
-+      if (ret) {
-+              dev_err(&client->dev, "%s: failed to enable regulators\n",
-+                      __func__);
-+              goto xclk_off;
-+      }
-+
-+      imx219_power(imx219, true);
-+      msleep(IMX219_XCLR_DELAY_MS);
-+
-+      return 0;
-+xclk_off:
-+      clk_disable_unprepare(imx219->xclk);
-+      return ret;
-+}
-+
-+static void imx219_set_power_off(struct imx219 *imx219)
-+{
-+      imx219_power(imx219, false);
-+      regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+      clk_disable_unprepare(imx219->xclk);
-+}
-+
-+static int imx219_set_power(struct imx219 *imx219, bool on)
-+{
-+      int ret = 0;
-+
-+      if (on) {
-+              ret = imx219_set_power_on(imx219);
-+              if (ret)
-+                      return ret;
-+      } else {
-+              imx219_set_power_off(imx219);
-+      }
-+
-+      return 0;
-+}
-+
-+/* Open sub-device */
-+static int imx219_s_power(struct v4l2_subdev *sd, int on)
++/* Get bayer order based on flip setting. */
++static u32 imx219_get_format_code(struct imx219 *imx219)
 +{
-+      struct imx219 *imx219 = to_imx219(sd);
-+      int ret = 0;
-+
-+      mutex_lock(&imx219->mutex);
-+
 +      /*
-+       * If the power count is modified from 0 to != 0 or from != 0 to 0,
-+       * update the power state.
++       * Only one bayer order is supported.
++       * It depends on the flip settings.
 +       */
-+      if (imx219->power_count == !on) {
-+              ret = imx219_set_power(imx219, !!on);
-+              if (ret)
-+                      goto out;
-+      }
++      static const u32 codes[2][2] = {
++              { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
++              { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
++      };
 +
-+      /* Update the power count. */
-+      imx219->power_count += on ? 1 : -1;
-+      WARN_ON(imx219->power_count < 0);
-+out:
-+      mutex_unlock(&imx219->mutex);
-+
-+      return ret;
++      lockdep_assert_held(&imx219->mutex);
++      return codes[imx219->vflip->val][imx219->hflip->val];
 +}
 +
 +static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 +{
++      struct imx219 *imx219 = to_imx219(sd);
 +      struct v4l2_mbus_framefmt *try_fmt =
 +              v4l2_subdev_get_try_format(sd, fh->pad, 0);
 +
++      mutex_lock(&imx219->mutex);
++
 +      /* Initialize try_fmt */
 +      try_fmt->width = supported_modes[0].width;
 +      try_fmt->height = supported_modes[0].height;
-+      try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      try_fmt->code = imx219_get_format_code(imx219);
 +      try_fmt->field = V4L2_FIELD_NONE;
 +
++      mutex_unlock(&imx219->mutex);
++
 +      return 0;
 +}
 +
@@ -616,7 +618,20 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      struct imx219 *imx219 =
 +              container_of(ctrl->handler, struct imx219, ctrl_handler);
 +      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+      int ret = 0;
++      int ret;
++
++      if (ctrl->id == V4L2_CID_VBLANK) {
++              int exposure_max, exposure_def;
++
++              /* Update max exposure while meeting expected vblanking */
++              exposure_max = imx219->mode->height + ctrl->val - 4;
++              exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++                      exposure_max : IMX219_EXPOSURE_DEFAULT;
++              __v4l2_ctrl_modify_range(imx219->exposure,
++                                       imx219->exposure->minimum,
++                                       exposure_max, imx219->exposure->step,
++                                       exposure_def);
++      }
 +
 +      /*
 +       * Applying V4L2 control value only happens
@@ -643,6 +658,33 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                                     IMX219_REG_VALUE_16BIT,
 +                                     imx219_test_pattern_val[ctrl->val]);
 +              break;
++      case V4L2_CID_HFLIP:
++      case V4L2_CID_VFLIP:
++              ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
++                                     imx219->hflip->val |
++                                     imx219->vflip->val << 1);
++              break;
++      case V4L2_CID_VBLANK:
++              ret = imx219_write_reg(imx219, IMX219_REG_VTS,
++                                     IMX219_REG_VALUE_16BIT,
++                                     imx219->mode->height + ctrl->val);
++              break;
++      case V4L2_CID_TEST_PATTERN_RED:
++              ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
++                                     IMX219_REG_VALUE_16BIT, ctrl->val);
++              break;
++      case V4L2_CID_TEST_PATTERN_GREENR:
++              ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
++                                     IMX219_REG_VALUE_16BIT, ctrl->val);
++              break;
++      case V4L2_CID_TEST_PATTERN_BLUE:
++              ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
++                                     IMX219_REG_VALUE_16BIT, ctrl->val);
++              break;
++      case V4L2_CID_TEST_PATTERN_GREENB:
++              ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
++                                     IMX219_REG_VALUE_16BIT, ctrl->val);
++              break;
 +      default:
 +              dev_info(&client->dev,
 +                       "ctrl(id:0x%x,val:0x%x) is not handled\n",
@@ -664,11 +706,16 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                               struct v4l2_subdev_pad_config *cfg,
 +                               struct v4l2_subdev_mbus_code_enum *code)
 +{
-+      /* Only one bayer order(GRBG) is supported */
++      struct imx219 *imx219 = to_imx219(sd);
++
++      /*
++       * Only one bayer order is supported (though it depends on the flip
++       * settings)
++       */
 +      if (code->index > 0)
 +              return -EINVAL;
 +
-+      code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      code->code = imx219_get_format_code(imx219);
 +
 +      return 0;
 +}
@@ -677,10 +724,12 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                                struct v4l2_subdev_pad_config *cfg,
 +                                struct v4l2_subdev_frame_size_enum *fse)
 +{
++      struct imx219 *imx219 = to_imx219(sd);
++
 +      if (fse->index >= ARRAY_SIZE(supported_modes))
 +              return -EINVAL;
 +
-+      if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
++      if (fse->code != imx219_get_format_code(imx219))
 +              return -EINVAL;
 +
 +      fse->min_width = supported_modes[fse->index].width;
@@ -691,24 +740,41 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      return 0;
 +}
 +
-+static void imx219_update_pad_format(const struct imx219_mode *mode,
++static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
++{
++      fmt->colorspace = V4L2_COLORSPACE_SRGB;
++      fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
++      fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
++                                                        fmt->colorspace,
++                                                        fmt->ycbcr_enc);
++      fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
++}
++
++static void imx219_update_pad_format(struct imx219 *imx219,
++                                   const struct imx219_mode *mode,
 +                                   struct v4l2_subdev_format *fmt)
 +{
 +      fmt->format.width = mode->width;
 +      fmt->format.height = mode->height;
-+      fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      fmt->format.code = imx219_get_format_code(imx219);
 +      fmt->format.field = V4L2_FIELD_NONE;
++
++      imx219_reset_colorspace(&fmt->format);
 +}
 +
 +static int __imx219_get_pad_format(struct imx219 *imx219,
 +                                 struct v4l2_subdev_pad_config *cfg,
 +                                 struct v4l2_subdev_format *fmt)
 +{
-+      if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-+              fmt->format = *v4l2_subdev_get_try_format(&imx219->sd, cfg,
-+                                                        fmt->pad);
-+      else
-+              imx219_update_pad_format(imx219->mode, fmt);
++      if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
++              struct v4l2_mbus_framefmt *try_fmt =
++                      v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
++              /* update the code which could change due to vflip or hflip: */
++              try_fmt->code = imx219_get_format_code(imx219);
++              fmt->format = *try_fmt;
++      } else {
++              imx219_update_pad_format(imx219, imx219->mode, fmt);
++      }
 +
 +      return 0;
 +}
@@ -734,22 +800,45 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      struct imx219 *imx219 = to_imx219(sd);
 +      const struct imx219_mode *mode;
 +      struct v4l2_mbus_framefmt *framefmt;
++      int exposure_max, exposure_def, hblank;
 +
 +      mutex_lock(&imx219->mutex);
 +
-+      /* Only one raw bayer(BGGR) order is supported */
-+      fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      /* Bayer order varies with flips */
++      fmt->format.code = imx219_get_format_code(imx219);
 +
 +      mode = v4l2_find_nearest_size(supported_modes,
 +                                    ARRAY_SIZE(supported_modes),
 +                                    width, height,
 +                                    fmt->format.width, fmt->format.height);
-+      imx219_update_pad_format(mode, fmt);
++      imx219_update_pad_format(imx219, mode, fmt);
 +      if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 +              framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
 +              *framefmt = fmt->format;
-+      } else {
++      } else if (imx219->mode != mode) {
 +              imx219->mode = mode;
++              /* Update limits and set FPS to default */
++              __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
++                                       IMX219_VTS_MAX - mode->height, 1,
++                                       mode->vts_def - mode->height);
++              __v4l2_ctrl_s_ctrl(imx219->vblank,
++                                 mode->vts_def - mode->height);
++              /* Update max exposure while meeting expected vblanking */
++              exposure_max = mode->vts_def - 4;
++              exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++                      exposure_max : IMX219_EXPOSURE_DEFAULT;
++              __v4l2_ctrl_modify_range(imx219->exposure,
++                                       imx219->exposure->minimum,
++                                       exposure_max, imx219->exposure->step,
++                                       exposure_def);
++              /*
++               * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
++               * depends on mode->width only, and is not changeble in any
++               * way other than changing the mode.
++               */
++              hblank = IMX219_PPL_DEFAULT - mode->width;
++              __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
++                                       hblank);
 +      }
 +
 +      mutex_unlock(&imx219->mutex);
@@ -757,7 +846,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      return 0;
 +}
 +
-+/* Start streaming */
 +static int imx219_start_streaming(struct imx219 *imx219)
 +{
 +      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -772,15 +860,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +              return ret;
 +      }
 +
-+      /*
-+       * Set VTS appropriately for frame rate control.
-+       * Currently fixed per mode.
-+       */
-+      ret = imx219_write_reg(imx219, IMX219_REG_VTS,
-+                             IMX219_REG_VALUE_16BIT, imx219->mode->vts_def);
-+      if (ret)
-+              return ret;
-+
 +      /* Apply customized values from user */
 +      ret =  __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
 +      if (ret)
@@ -791,8 +870,7 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                              IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
 +}
 +
-+/* Stop streaming */
-+static int imx219_stop_streaming(struct imx219 *imx219)
++static void imx219_stop_streaming(struct imx219 *imx219)
 +{
 +      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
 +      int ret;
@@ -802,12 +880,6 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                             IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
 +      if (ret)
 +              dev_err(&client->dev, "%s failed to set stream\n", __func__);
-+
-+      /*
-+       * Return success even if it was an error, as there is nothing the
-+       * caller can do about it.
-+       */
-+      return 0;
 +}
 +
 +static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
@@ -834,26 +906,79 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +               * and then start streaming.
 +               */
 +              ret = imx219_start_streaming(imx219);
-+              if (ret) {
-+                      pm_runtime_put(&client->dev);
-+                      goto err_unlock;
-+              }
++              if (ret)
++                      goto err_rpm_put;
 +      } else {
 +              imx219_stop_streaming(imx219);
 +              pm_runtime_put(&client->dev);
 +      }
 +
 +      imx219->streaming = enable;
++
++      /* vflip and hflip cannot change during streaming */
++      __v4l2_ctrl_grab(imx219->vflip, enable);
++      __v4l2_ctrl_grab(imx219->hflip, enable);
++
 +      mutex_unlock(&imx219->mutex);
 +
 +      return ret;
 +
++err_rpm_put:
++      pm_runtime_put(&client->dev);
 +err_unlock:
 +      mutex_unlock(&imx219->mutex);
 +
 +      return ret;
 +}
 +
++/* Power/clock management functions */
++static int imx219_power_on(struct device *dev)
++{
++      struct i2c_client *client = to_i2c_client(dev);
++      struct v4l2_subdev *sd = i2c_get_clientdata(client);
++      struct imx219 *imx219 = to_imx219(sd);
++      int ret;
++
++      ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
++                                  imx219->supplies);
++      if (ret) {
++              dev_err(&client->dev, "%s: failed to enable regulators\n",
++                      __func__);
++              return ret;
++      }
++
++      ret = clk_prepare_enable(imx219->xclk);
++      if (ret) {
++              dev_err(&client->dev, "%s: failed to enable clock\n",
++                      __func__);
++              goto reg_off;
++      }
++
++      gpiod_set_value_cansleep(imx219->reset_gpio, 1);
++      usleep_range(IMX219_XCLR_MIN_DELAY_US,
++                   IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
++
++      return 0;
++
++reg_off:
++      regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
++
++      return ret;
++}
++
++static int imx219_power_off(struct device *dev)
++{
++      struct i2c_client *client = to_i2c_client(dev);
++      struct v4l2_subdev *sd = i2c_get_clientdata(client);
++      struct imx219 *imx219 = to_imx219(sd);
++
++      gpiod_set_value_cansleep(imx219->reset_gpio, 0);
++      regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
++      clk_disable_unprepare(imx219->xclk);
++
++      return 0;
++}
++
 +static int __maybe_unused imx219_suspend(struct device *dev)
 +{
 +      struct i2c_client *client = to_i2c_client(dev);
@@ -884,13 +1009,14 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +error:
 +      imx219_stop_streaming(imx219);
 +      imx219->streaming = 0;
++
 +      return ret;
 +}
 +
 +static int imx219_get_regulators(struct imx219 *imx219)
 +{
 +      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+      int i;
++      unsigned int i;
 +
 +      for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
 +              imx219->supplies[i].supply = imx219_supply_name[i];
@@ -907,31 +1033,26 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      int ret;
 +      u32 val;
 +
-+      ret = imx219_set_power_on(imx219);
-+      if (ret)
-+              return ret;
-+
 +      ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
 +                            IMX219_REG_VALUE_16BIT, &val);
 +      if (ret) {
 +              dev_err(&client->dev, "failed to read chip id %x\n",
 +                      IMX219_CHIP_ID);
-+              goto power_off;
++              return ret;
 +      }
 +
 +      if (val != IMX219_CHIP_ID) {
 +              dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
 +                      IMX219_CHIP_ID, val);
-+              ret = -EIO;
++              return -EIO;
 +      }
 +
-+power_off:
-+      imx219_set_power_off(imx219);
-+      return ret;
++      return 0;
 +}
 +
 +static const struct v4l2_subdev_core_ops imx219_core_ops = {
-+      .s_power = imx219_s_power,
++      .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
++      .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 +};
 +
 +static const struct v4l2_subdev_video_ops imx219_video_ops = {
@@ -960,22 +1081,44 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +{
 +      struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
 +      struct v4l2_ctrl_handler *ctrl_hdlr;
-+      int ret;
++      unsigned int height = imx219->mode->height;
++      int exposure_max, exposure_def, hblank;
++      int i, ret;
 +
 +      ctrl_hdlr = &imx219->ctrl_handler;
-+      ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
++      ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
 +      if (ret)
 +              return ret;
 +
 +      mutex_init(&imx219->mutex);
 +      ctrl_hdlr->lock = &imx219->mutex;
 +
++      /* By default, PIXEL_RATE is read only */
++      imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                             V4L2_CID_PIXEL_RATE,
++                                             IMX219_PIXEL_RATE,
++                                             IMX219_PIXEL_RATE, 1,
++                                             IMX219_PIXEL_RATE);
++
++      /* Initial vblank/hblank/exposure parameters based on current mode */
++      imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                         V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
++                                         IMX219_VTS_MAX - height, 1,
++                                         imx219->mode->vts_def - height);
++      hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
++      imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                         V4L2_CID_HBLANK, hblank, hblank,
++                                         1, hblank);
++      if (imx219->hblank)
++              imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
++      exposure_max = imx219->mode->vts_def - 4;
++      exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++              exposure_max : IMX219_EXPOSURE_DEFAULT;
 +      imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
 +                                           V4L2_CID_EXPOSURE,
-+                                           IMX219_EXPOSURE_MIN,
-+                                           IMX219_EXPOSURE_MAX,
++                                           IMX219_EXPOSURE_MIN, exposure_max,
 +                                           IMX219_EXPOSURE_STEP,
-+                                           IMX219_EXPOSURE_DEFAULT);
++                                           exposure_def);
 +
 +      v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
 +                        IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
@@ -985,10 +1128,35 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +                        IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
 +                        IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
 +
++      imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                        V4L2_CID_HFLIP, 0, 1, 1, 0);
++      if (imx219->hflip)
++              imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
++
++      imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                        V4L2_CID_VFLIP, 0, 1, 1, 0);
++      if (imx219->vflip)
++              imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
++
 +      v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
 +                                   V4L2_CID_TEST_PATTERN,
 +                                   ARRAY_SIZE(imx219_test_pattern_menu) - 1,
 +                                   0, 0, imx219_test_pattern_menu);
++      for (i = 0; i < 4; i++) {
++              /*
++               * The assumption is that
++               * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
++               * V4L2_CID_TEST_PATTERN_BLUE   == V4L2_CID_TEST_PATTERN_RED + 2
++               * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
++               */
++              v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++                                V4L2_CID_TEST_PATTERN_RED + i,
++                                IMX219_TESTP_COLOUR_MIN,
++                                IMX219_TESTP_COLOUR_MAX,
++                                IMX219_TESTP_COLOUR_STEP,
++                                IMX219_TESTP_COLOUR_MAX);
++              /* The "Solid color" pattern is white by default */
++      }
 +
 +      if (ctrl_hdlr->error) {
 +              ret = ctrl_hdlr->error;
@@ -1014,11 +1182,56 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      mutex_destroy(&imx219->mutex);
 +}
 +
-+static int imx219_probe(struct i2c_client *client,
-+                      const struct i2c_device_id *id)
++static int imx219_check_hwcfg(struct device *dev)
 +{
-+      struct device *dev = &client->dev;
 +      struct fwnode_handle *endpoint;
++      struct v4l2_fwnode_endpoint ep_cfg = {
++              .bus_type = V4L2_MBUS_CSI2_DPHY
++      };
++      int ret = -EINVAL;
++
++      endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
++      if (!endpoint) {
++              dev_err(dev, "endpoint node not found\n");
++              return -EINVAL;
++      }
++
++      if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
++              dev_err(dev, "could not parse endpoint\n");
++              goto error_out;
++      }
++
++      /* Check the number of MIPI CSI2 data lanes */
++      if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
++              dev_err(dev, "only 2 data lanes are currently supported\n");
++              goto error_out;
++      }
++
++      /* Check the link frequency set in device tree */
++      if (!ep_cfg.nr_of_link_frequencies) {
++              dev_err(dev, "link-frequency property not found in DT\n");
++              goto error_out;
++      }
++
++      if (ep_cfg.nr_of_link_frequencies != 1 ||
++          ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
++              dev_err(dev, "Link frequency not supported: %lld\n",
++                      ep_cfg.link_frequencies[0]);
++              goto error_out;
++      }
++
++      ret = 0;
++
++error_out:
++      v4l2_fwnode_endpoint_free(&ep_cfg);
++      fwnode_handle_put(endpoint);
++
++      return ret;
++}
++
++static int imx219_probe(struct i2c_client *client)
++{
++      struct device *dev = &client->dev;
 +      struct imx219 *imx219;
 +      int ret;
 +
@@ -1026,57 +1239,54 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      if (!imx219)
 +              return -ENOMEM;
 +
-+      /* Initialize subdev */
 +      v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
 +
-+      /* Get CSI2 bus config */
-+      endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+                                                NULL);
-+      if (!endpoint) {
-+              dev_err(dev, "endpoint node not found\n");
++      /* Check the hardware configuration in device tree */
++      if (imx219_check_hwcfg(dev))
 +              return -EINVAL;
-+      }
-+
-+      ret = v4l2_fwnode_endpoint_parse(endpoint, &imx219->ep);
-+      fwnode_handle_put(endpoint);
-+      if (ret) {
-+              dev_err(dev, "Could not parse endpoint\n");
-+              return ret;
-+      }
 +
 +      /* Get system clock (xclk) */
-+      imx219->xclk = devm_clk_get(dev, "xclk");
++      imx219->xclk = devm_clk_get(dev, NULL);
 +      if (IS_ERR(imx219->xclk)) {
 +              dev_err(dev, "failed to get xclk\n");
 +              return PTR_ERR(imx219->xclk);
 +      }
 +
 +      imx219->xclk_freq = clk_get_rate(imx219->xclk);
-+      if (imx219->xclk_freq != 24000000) {
++      if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
 +              dev_err(dev, "xclk frequency not supported: %d Hz\n",
 +                      imx219->xclk_freq);
 +              return -EINVAL;
 +      }
 +
 +      ret = imx219_get_regulators(imx219);
-+      if (ret)
++      if (ret) {
++              dev_err(dev, "failed to get regulators\n");
 +              return ret;
++      }
 +
-+      /* request optional power down pin */
-+      imx219->xclr_gpio = devm_gpiod_get_optional(dev, "xclr",
-+                                                  GPIOD_OUT_HIGH);
++      /* Request optional enable pin */
++      imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
++                                                   GPIOD_OUT_HIGH);
 +
-+      /* Check module identity */
-+      ret = imx219_identify_module(imx219);
++      /*
++       * The sensor must be powered for imx219_identify_module()
++       * to be able to read the CHIP_ID register
++       */
++      ret = imx219_power_on(dev);
 +      if (ret)
 +              return ret;
 +
++      ret = imx219_identify_module(imx219);
++      if (ret)
++              goto error_power_off;
++
 +      /* Set default mode to max resolution */
 +      imx219->mode = &supported_modes[0];
 +
 +      ret = imx219_init_controls(imx219);
 +      if (ret)
-+              return ret;
++              goto error_power_off;
 +
 +      /* Initialize subdev */
 +      imx219->sd.internal_ops = &imx219_internal_ops;
@@ -1087,16 +1297,21 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
 +
 +      ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
-+      if (ret)
++      if (ret) {
++              dev_err(dev, "failed to init entity pads: %d\n", ret);
 +              goto error_handler_free;
++      }
 +
 +      ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
-+      if (ret < 0)
++      if (ret < 0) {
++              dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
 +              goto error_media_entity;
++      }
 +
-+      pm_runtime_set_active(&client->dev);
-+      pm_runtime_enable(&client->dev);
-+      pm_runtime_idle(&client->dev);
++      /* Enable runtime PM and turn off the device */
++      pm_runtime_set_active(dev);
++      pm_runtime_enable(dev);
++      pm_runtime_idle(dev);
 +
 +      return 0;
 +
@@ -1106,6 +1321,9 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +error_handler_free:
 +      imx219_free_controls(imx219);
 +
++error_power_off:
++      imx219_power_off(dev);
++
 +      return ret;
 +}
 +
@@ -1119,6 +1337,8 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +      imx219_free_controls(imx219);
 +
 +      pm_runtime_disable(&client->dev);
++      if (!pm_runtime_status_suspended(&client->dev))
++              imx219_power_off(&client->dev);
 +      pm_runtime_set_suspended(&client->dev);
 +
 +      return 0;
@@ -1130,17 +1350,23 @@ Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
 +};
 +MODULE_DEVICE_TABLE(of, imx219_dt_ids);
 +
++static const struct dev_pm_ops imx219_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
++      SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
++};
++
 +static struct i2c_driver imx219_i2c_driver = {
 +      .driver = {
 +              .name = "imx219",
 +              .of_match_table = imx219_dt_ids,
++              .pm = &imx219_pm_ops,
 +      },
-+      .probe = imx219_probe,
++      .probe_new = imx219_probe,
 +      .remove = imx219_remove,
 +};
 +
 +module_i2c_driver(imx219_i2c_driver);
 +
-+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org");
++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com");
 +MODULE_DESCRIPTION("Sony IMX219 sensor driver");
 +MODULE_LICENSE("GPL v2");
diff --git a/target/linux/bcm27xx/patches-5.4/950-0465-overlays-imx219-Correct-link-frequency-to-match-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0465-overlays-imx219-Correct-link-frequency-to-match-the-.patch
new file mode 100644 (file)
index 0000000..e9eed21
--- /dev/null
@@ -0,0 +1,25 @@
+From eae83133532e44adae2f632b2168119a4c7249a2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 11 Mar 2020 12:07:57 +0000
+Subject: [PATCH] overlays: imx219: Correct link frequency to match the
+ upstream driver
+
+The upstream driver is checking the link frequency parameter, and
+the overlay had the wrong value.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/imx219-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/imx219-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts
+@@ -40,7 +40,7 @@
+                                               data-lanes = <1 2>;
+                                               clock-noncontinuous;
+                                               link-frequencies =
+-                                                      /bits/ 64 <297000000>;
++                                                      /bits/ 64 <456000000>;
+                                       };
+                               };
+                       };
diff --git a/target/linux/bcm27xx/patches-5.4/950-0466-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch b/target/linux/bcm27xx/patches-5.4/950-0466-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch
new file mode 100644 (file)
index 0000000..e9b8a76
--- /dev/null
@@ -0,0 +1,26 @@
+From 61113c5463166d734dc6560574f5fb1536bae795 Mon Sep 17 00:00:00 2001
+From: Nataliya Korovkina <malus.brandywine@gmail.com>
+Date: Thu, 12 Mar 2020 17:22:53 -0400
+Subject: [PATCH] Kbuild: Allow .dtbo overlays to be built, adjust.
+
+This is adjustment to commit
+d368ceaacdccd7732dc97d1d7987bdf7149d62e3 "kbuild: Allow .dtbo overlays to be built piecemeal"
+
+prepare3 target has gone from mainline tree in branch 5.4.y
+
+Signed-off-by: Nataliya Korovkina <malus.brandywine@gmail.com>
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -1238,7 +1238,7 @@ ifneq ($(dtstree),)
+ %.dtb: include/config/kernel.release scripts_dtc
+       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
+-%.dtbo: prepare3 scripts_dtc
++%.dtbo: include/config/kernel.release scripts_dtc
+       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
+ PHONY += dtbs dtbs_install dt_binding_check
diff --git a/target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch b/target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch
new file mode 100644 (file)
index 0000000..c7e10cb
--- /dev/null
@@ -0,0 +1,74 @@
+From 23f717168dc55f69ad517d3ab5f412d04a5afc0e Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.org>
+Date: Wed, 15 Jan 2020 13:40:38 +0000
+Subject: [PATCH] media: ov5647: Fix return codes from
+ ov5647_write/ov5647_read functions.
+
+Previously they were returning positive non-zero codes for success,
+which were getting passed up the call stack. Since release 4.19,
+do_dentry_open (fs/open.c) has been catching these and flagging an
+error. (So this driver has been broken since that date.)
+
+Fixes: 3c2472a [media] media: i2c: Add support for OV5647 sensor
+Signed-off-by: David Plowman <david.plowman@raspberrypi.org>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -214,9 +214,18 @@ static int ov5647_write(struct v4l2_subd
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       ret = i2c_master_send(client, data, 3);
+-      if (ret < 0)
++      /*
++       * Writing the wrong number of bytes also needs to be flagged as an
++       * error. Success needs to produce a 0 return code.
++       */
++      if (ret == 3) {
++              ret = 0;
++      } else {
+               dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+                               __func__, reg);
++              if (ret >= 0)
++                      ret = -EINVAL;
++      }
+       return ret;
+ }
+@@ -228,16 +237,31 @@ static int ov5647_read(struct v4l2_subde
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       ret = i2c_master_send(client, data_w, 2);
+-      if (ret < 0) {
++      /*
++       * A negative return code, or sending the wrong number of bytes, both
++       * count as an error.
++       */
++      if (ret != 2) {
+               dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+                       __func__, reg);
++              if (ret >= 0)
++                      ret = -EINVAL;
+               return ret;
+       }
+       ret = i2c_master_recv(client, val, 1);
+-      if (ret < 0)
++      /*
++       * The only return value indicating success is 1. Anything else, even
++       * a non-negative value, indicates something went wrong.
++       */
++      if (ret == 1) {
++              ret = 0;
++      } else {
+               dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+                               __func__, reg);
++              if (ret >= 0)
++                      ret = -EINVAL;
++      }
+       return ret;
+ }
diff --git a/target/linux/bcm27xx/patches-5.4/950-0468-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch b/target/linux/bcm27xx/patches-5.4/950-0468-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch
new file mode 100644 (file)
index 0000000..5846e96
--- /dev/null
@@ -0,0 +1,407 @@
+From 9e584d9de3387588bf455d3c45ec6a092bfa4266 Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:30:53 +0000
+Subject: [PATCH] media: ov5647: Add basic support for multiple sensor
+ modes.
+
+Specifically:
+
+Added a structure ov5647_mode and a list of supported_modes (though no
+actual new modes as yet). The state object points to the "current mode".
+
+ov5647_enum_mbus_code, ov5647_enum_frame_size, ov5647_set_fmt and
+ov5647_get_fmt all needed upgrading to cope with multiple modes.
+
+__sensor_init (which writes all the registers) is now called by
+ov5647_stream_on (once the mode is known) rather than by
+ov5647_sensor_power.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 268 ++++++++++++++++++++++++++++---------
+ 1 file changed, 202 insertions(+), 66 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -86,13 +86,17 @@ struct regval_list {
+       u8 data;
+ };
++struct ov5647_mode {
++      struct v4l2_mbus_framefmt       format;
++      struct regval_list              *reg_list;
++      unsigned int                    num_regs;
++};
++
+ struct ov5647 {
+       struct v4l2_subdev              sd;
+       struct media_pad                pad;
+       struct mutex                    lock;
+-      struct v4l2_mbus_framefmt       format;
+-      unsigned int                    width;
+-      unsigned int                    height;
++      const struct ov5647_mode        *mode;
+       int                             power_count;
+       struct clk                      *xclk;
+       struct gpio_desc                *pwdn;
+@@ -207,6 +211,32 @@ static struct regval_list ov5647_640x480
+       {0x0100, 0x01},
+ };
++static struct ov5647_mode supported_modes_8bit[] = {
++      /*
++       * Original 8-bit VGA mode
++       * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image.
++       */
++      {
++              {
++                      .code = MEDIA_BUS_FMT_SBGGR8_1X8,
++                      .colorspace = V4L2_COLORSPACE_SRGB,
++                      .field = V4L2_FIELD_NONE,
++                      .width = 640,
++                      .height = 480
++              },
++              ov5647_640x480,
++              ARRAY_SIZE(ov5647_640x480)
++      },
++      /* more modes below here... */
++};
++
++static struct ov5647_mode supported_modes_10bit[] = {
++      /* no 10-bit modes yet */
++};
++
++/* Use original 8-bit VGA mode as default. */
++#define OV5647_DEFAULT_MODE (&supported_modes_8bit[0])
++
+ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+ {
+       int ret;
+@@ -293,12 +323,55 @@ static int ov5647_set_virtual_channel(st
+       return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
+ }
++static int __sensor_init(struct v4l2_subdev *sd)
++{
++      int ret;
++      u8 resetval, rdval;
++      struct i2c_client *client = v4l2_get_subdevdata(sd);
++      struct ov5647 *state = to_state(sd);
++
++      ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
++      if (ret < 0)
++              return ret;
++
++      ret = ov5647_write_array(sd, state->mode->reg_list,
++                               state->mode->num_regs);
++      if (ret < 0) {
++              dev_err(&client->dev, "write sensor default regs error\n");
++              return ret;
++      }
++
++      ret = ov5647_set_virtual_channel(sd, 0);
++      if (ret < 0)
++              return ret;
++
++      ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
++      if (ret < 0)
++              return ret;
++
++      if (!(resetval & 0x01)) {
++              dev_err(&client->dev, "Device was in SW standby");
++              ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
++              if (ret < 0)
++                      return ret;
++      }
++
++      return 0;
++}
++
+ static int ov5647_stream_on(struct v4l2_subdev *sd)
+ {
++      struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5647 *ov5647 = to_state(sd);
+       u8 val = MIPI_CTRL00_BUS_IDLE;
+       int ret;
++      ret = __sensor_init(sd);
++      if (ret < 0) {
++              dev_err(&client->dev, "sensor_init failed\n");
++              return ret;
++      }
++
+       if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
+               val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+                      MIPI_CTRL00_LINE_SYNC_ENABLE;
+@@ -347,44 +420,6 @@ static int set_sw_standby(struct v4l2_su
+       return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
+ }
+-static int __sensor_init(struct v4l2_subdev *sd)
+-{
+-      int ret;
+-      u8 resetval, rdval;
+-      struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+-      ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
+-      if (ret < 0)
+-              return ret;
+-
+-      ret = ov5647_write_array(sd, ov5647_640x480,
+-                                      ARRAY_SIZE(ov5647_640x480));
+-      if (ret < 0) {
+-              dev_err(&client->dev, "write sensor default regs error\n");
+-              return ret;
+-      }
+-
+-      ret = ov5647_set_virtual_channel(sd, 0);
+-      if (ret < 0)
+-              return ret;
+-
+-      ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
+-      if (ret < 0)
+-              return ret;
+-
+-      if (!(resetval & 0x01)) {
+-              dev_err(&client->dev, "Device was in SW standby");
+-              ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
+-              if (ret < 0)
+-                      return ret;
+-      }
+-
+-      /*
+-       * stream off to make the clock lane into LP-11 state.
+-       */
+-      return ov5647_stream_off(sd);
+-}
+-
+ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
+ {
+       int ret = 0;
+@@ -408,7 +443,7 @@ static int ov5647_sensor_power(struct v4
+               }
+               ret = ov5647_write_array(sd, sensor_oe_enable_regs,
+-                              ARRAY_SIZE(sensor_oe_enable_regs));
++                                       ARRAY_SIZE(sensor_oe_enable_regs));
+               if (ret < 0) {
+                       clk_disable_unprepare(ov5647->xclk);
+                       dev_err(&client->dev,
+@@ -416,7 +451,10 @@ static int ov5647_sensor_power(struct v4
+                       goto out;
+               }
+-              ret = __sensor_init(sd);
++              /*
++               * Ensure streaming off to make clock lane go into LP-11 state.
++               */
++              ret = ov5647_stream_off(sd);
+               if (ret < 0) {
+                       clk_disable_unprepare(ov5647->xclk);
+                       dev_err(&client->dev,
+@@ -427,7 +465,7 @@ static int ov5647_sensor_power(struct v4
+               dev_dbg(&client->dev, "OV5647 power off\n");
+               ret = ov5647_write_array(sd, sensor_oe_disable_regs,
+-                              ARRAY_SIZE(sensor_oe_disable_regs));
++                                       ARRAY_SIZE(sensor_oe_disable_regs));
+               if (ret < 0)
+                       dev_dbg(&client->dev, "disable oe failed\n");
+@@ -489,10 +527,19 @@ static const struct v4l2_subdev_core_ops
+ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
+ {
++      struct ov5647 *state = to_state(sd);
++      int ret = 0;
++
++      mutex_lock(&state->lock);
++
+       if (enable)
+-              return ov5647_stream_on(sd);
++              ret = ov5647_stream_on(sd);
+       else
+-              return ov5647_stream_off(sd);
++              ret = ov5647_stream_off(sd);
++
++      mutex_unlock(&state->lock);
++
++      return ret;
+ }
+ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
+@@ -503,38 +550,127 @@ static int ov5647_enum_mbus_code(struct
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_mbus_code_enum *code)
+ {
+-      if (code->index > 0)
++      if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit))
++              code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
++      else if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit) == 0 &&
++               ARRAY_SIZE(supported_modes_10bit))
++              code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      else if (code->index == 1 && ARRAY_SIZE(supported_modes_8bit) &&
++               ARRAY_SIZE(supported_modes_10bit))
++              code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++      else
+               return -EINVAL;
+-      code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
++      return 0;
++}
++
++static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
++                                struct v4l2_subdev_pad_config *cfg,
++                                struct v4l2_subdev_frame_size_enum *fse)
++{
++      struct ov5647_mode *mode = NULL;
++
++      if (fse->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
++              if (fse->index >= ARRAY_SIZE(supported_modes_8bit))
++                      return -EINVAL;
++              mode = &supported_modes_8bit[fse->index];
++      } else if (fse->code == MEDIA_BUS_FMT_SBGGR10_1X10) {
++              if (fse->index >= ARRAY_SIZE(supported_modes_10bit))
++                      return -EINVAL;
++              mode = &supported_modes_10bit[fse->index];
++      } else {
++              return -EINVAL;
++      }
++
++      fse->min_width = mode->format.width;
++      fse->max_width = fse->min_width;
++      fse->min_height = mode->format.height;
++      fse->max_height = fse->min_height;
++
++      return 0;
++}
++
++static int ov5647_set_fmt(struct v4l2_subdev *sd,
++                        struct v4l2_subdev_pad_config *cfg,
++                        struct v4l2_subdev_format *format)
++{
++      struct v4l2_mbus_framefmt *fmt = &format->format;
++      struct ov5647 *state = to_state(sd);
++      struct v4l2_mbus_framefmt *framefmt;
++      const struct ov5647_mode *mode_8bit, *mode_10bit, *mode = NULL;
++
++      if (format->pad != 0)
++              return -EINVAL;
++
++      mutex_lock(&state->lock);
++
++      /*
++       * Try to respect any given pixel format, otherwise try for a 10-bit
++       * mode.
++       */
++      mode_8bit = v4l2_find_nearest_size(supported_modes_8bit,
++                                         ARRAY_SIZE(supported_modes_8bit),
++                                         format.width, format.height,
++                                         format->format.width,
++                                         format->format.height);
++      mode_10bit = v4l2_find_nearest_size(supported_modes_10bit,
++                                          ARRAY_SIZE(supported_modes_10bit),
++                                          format.width, format.height,
++                                          format->format.width,
++                                          format->format.height);
++      if (format->format.code == MEDIA_BUS_FMT_SBGGR8_1X8 && mode_8bit)
++              mode = mode_8bit;
++      else if (format->format.code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
++               mode_10bit)
++              mode = mode_10bit;
++      else if (mode_10bit)
++              mode = mode_10bit;
++      else
++              mode = mode_8bit;
++
++      if (!mode)
++              return -EINVAL;
++
++      *fmt = mode->format;
++      if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
++              framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
++              *framefmt = format->format;
++      } else {
++              state->mode = mode;
++      }
++
++      mutex_unlock(&state->lock);
+       return 0;
+ }
+-static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
+-                            struct v4l2_subdev_pad_config *cfg,
+-                            struct v4l2_subdev_format *format)
++static int ov5647_get_fmt(struct v4l2_subdev *sd,
++                        struct v4l2_subdev_pad_config *cfg,
++                        struct v4l2_subdev_format *format)
+ {
+       struct v4l2_mbus_framefmt *fmt = &format->format;
++      struct ov5647 *state = to_state(sd);
+       if (format->pad != 0)
+               return -EINVAL;
+-      /* Only one format is supported, so return that */
+-      memset(fmt, 0, sizeof(*fmt));
+-      fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+-      fmt->colorspace = V4L2_COLORSPACE_SRGB;
+-      fmt->field = V4L2_FIELD_NONE;
+-      fmt->width = 640;
+-      fmt->height = 480;
++      mutex_lock(&state->lock);
++
++      if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++              *fmt = *v4l2_subdev_get_try_format(sd, cfg, format->pad);
++      else
++              *fmt = state->mode->format;
++
++      mutex_unlock(&state->lock);
+       return 0;
+ }
+ static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
+       .enum_mbus_code = ov5647_enum_mbus_code,
+-      .set_fmt =        ov5647_set_get_fmt,
+-      .get_fmt =        ov5647_set_get_fmt,
++      .set_fmt =        ov5647_set_fmt,
++      .get_fmt =        ov5647_get_fmt,
++      .enum_frame_size = ov5647_enum_frame_size,
+ };
+ static const struct v4l2_subdev_ops ov5647_subdev_ops = {
+@@ -580,18 +716,15 @@ static int ov5647_open(struct v4l2_subde
+                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       struct v4l2_rect *crop =
+                               v4l2_subdev_get_try_crop(sd, fh->pad, 0);
++      struct ov5647 *state = to_state(sd);
+       crop->left = OV5647_COLUMN_START_DEF;
+       crop->top = OV5647_ROW_START_DEF;
+       crop->width = OV5647_WINDOW_WIDTH_DEF;
+       crop->height = OV5647_WINDOW_HEIGHT_DEF;
+-      format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+-
+-      format->width = OV5647_WINDOW_WIDTH_DEF;
+-      format->height = OV5647_WINDOW_HEIGHT_DEF;
+-      format->field = V4L2_FIELD_NONE;
+-      format->colorspace = V4L2_COLORSPACE_SRGB;
++      /* Set the default format to the same as the sensor. */
++      *format = state->mode->format;
+       return 0;
+ }
+@@ -660,6 +793,9 @@ static int ov5647_probe(struct i2c_clien
+       mutex_init(&sensor->lock);
++      /* Set the default mode before we init the subdev */
++      sensor->mode = OV5647_DEFAULT_MODE;
++
+       sd = &sensor->sd;
+       v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
+       sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0469-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch b/target/linux/bcm27xx/patches-5.4/950-0469-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch
new file mode 100644 (file)
index 0000000..907bab5
--- /dev/null
@@ -0,0 +1,277 @@
+From d9d333b717f220439868edd533994f2709b3a95f Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:23 +0000
+Subject: [PATCH] media: ov5647: Add V4L2 controls for analogue gain,
+ exposure and AWB
+
+Added basic v4l2_ctrl_handler infrastructure (there was none
+previously).
+
+Added controls to let AWB/AEC/AGC run in the sensor's auto mode or
+manually. Also controls to set exposure (in lines) and analogue gain
+(as a register code) from user code.
+
+Also delete registers (just the one) from the VGA mode register set
+that are now controlled by the new V4L2 controls.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 175 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 174 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -29,11 +29,13 @@
+ #include <linux/of_graph.h>
+ #include <linux/slab.h>
+ #include <linux/videodev2.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-fwnode.h>
+ #include <media/v4l2-image-sizes.h>
+ #include <media/v4l2-mediabus.h>
++
+ #define SENSOR_NAME "ov5647"
+ /*
+@@ -53,9 +55,16 @@
+ #define OV5647_REG_CHIPID_H           0x300A
+ #define OV5647_REG_CHIPID_L           0x300B
+ #define OV5640_REG_PAD_OUT            0x300D
++#define OV5647_REG_EXP_HI             0x3500
++#define OV5647_REG_EXP_MID            0x3501
++#define OV5647_REG_EXP_LO             0x3502
++#define OV5647_REG_AEC_AGC            0x3503
++#define OV5647_REG_GAIN_HI            0x350A
++#define OV5647_REG_GAIN_LO            0x350B
+ #define OV5647_REG_FRAME_OFF_NUMBER   0x4202
+ #define OV5647_REG_MIPI_CTRL00                0x4800
+ #define OV5647_REG_MIPI_CTRL14                0x4814
++#define OV5647_REG_AWB                        0x5001
+ #define REG_TERM 0xfffe
+ #define VAL_TERM 0xfe
+@@ -101,6 +110,7 @@ struct ov5647 {
+       struct clk                      *xclk;
+       struct gpio_desc                *pwdn;
+       unsigned int                    flags;
++      struct v4l2_ctrl_handler        ctrls;
+ };
+ static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+@@ -135,7 +145,6 @@ static struct regval_list ov5647_640x480
+       {0x3612, 0x59},
+       {0x3618, 0x00},
+       {0x5000, 0x06},
+-      {0x5001, 0x01},
+       {0x5002, 0x41},
+       {0x5003, 0x08},
+       {0x5a00, 0x08},
+@@ -372,6 +381,11 @@ static int ov5647_stream_on(struct v4l2_
+               return ret;
+       }
++      /* Apply customized values from user when stream starts */
++      ret =  __v4l2_ctrl_handler_setup(sd->ctrl_handler);
++      if (ret)
++              return ret;
++
+       if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
+               val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+                      MIPI_CTRL00_LINE_SYNC_ENABLE;
+@@ -753,6 +767,120 @@ static int ov5647_parse_dt(struct device
+       return ret;
+ }
++static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)
++{
++      /* non-zero turns on AWB */
++      return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);
++}
++
++static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)
++{
++      int ret;
++      u8 reg;
++
++      /* non-zero turns on AGC by clearing bit 1 */
++      ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
++      if (ret == 0)
++              ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
++                                 val ? reg & ~2 : reg | 2);
++
++      return ret;
++}
++
++static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)
++{
++      int ret;
++      u8 reg;
++
++      /* Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
++       * clearing bit 0
++       */
++      ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
++      if (ret == 0)
++              ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
++                                 val == V4L2_EXPOSURE_MANUAL ?
++                                 reg | 1 : reg & ~1);
++
++      return ret;
++}
++
++static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)
++{
++      int ret;
++
++      /* 10 bits of gain, 2 in the high register */
++      ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);
++      if (ret == 0)
++              ret = ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);
++
++      return ret;
++}
++
++static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)
++{
++      int ret;
++
++      /* Sensor has 20 bits, but the bottom 4 bits are fractions of a line
++       * which we leave as zero (and don't receive in "val").
++       */
++      ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);
++      if (ret == 0)
++              ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);
++      if (ret == 0)
++              ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);
++
++      return ret;
++}
++
++static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++      struct ov5647 *state = container_of(ctrl->handler,
++                                           struct ov5647, ctrls);
++      struct v4l2_subdev *sd = &state->sd;
++      struct i2c_client *client = v4l2_get_subdevdata(sd);
++      int ret = 0;
++
++      /* v4l2_ctrl_lock() locks our own mutex */
++
++      /*
++       * If the device is not powered up by the host driver do
++       * not apply any controls to H/W at this time. Instead
++       * the controls will be restored right after power-up.
++       */
++      if (state->power_count == 0)
++              return 0;
++
++      switch (ctrl->id) {
++      case V4L2_CID_AUTO_WHITE_BALANCE:
++              ret = ov5647_s_auto_white_balance(sd, ctrl->val);
++              break;
++      case V4L2_CID_AUTOGAIN:
++              ret = ov5647_s_autogain(sd, ctrl->val);
++              break;
++      case V4L2_CID_EXPOSURE_AUTO:
++              ret = ov5647_s_exposure_auto(sd, ctrl->val);
++              break;
++      case V4L2_CID_ANALOGUE_GAIN:
++              ret = ov5647_s_analogue_gain(sd, ctrl->val);
++              break;
++      case V4L2_CID_EXPOSURE:
++              ret = ov5647_s_exposure(sd, ctrl->val);
++              break;
++      default:
++              dev_info(&client->dev,
++                       "ctrl(id:0x%x,val:0x%x) is not handled\n",
++                       ctrl->id, ctrl->val);
++              ret = -EINVAL;
++              break;
++      }
++
++      return ret;
++}
++
++static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
++      .s_ctrl = ov5647_s_ctrl,
++};
++
+ static int ov5647_probe(struct i2c_client *client)
+ {
+       struct device *dev = &client->dev;
+@@ -761,6 +889,7 @@ static int ov5647_probe(struct i2c_clien
+       struct v4l2_subdev *sd;
+       struct device_node *np = client->dev.of_node;
+       u32 xclk_freq;
++      struct v4l2_ctrl *ctrl;
+       sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+       if (!sensor)
+@@ -793,6 +922,48 @@ static int ov5647_probe(struct i2c_clien
+       mutex_init(&sensor->lock);
++      /* Initialise controls. */
++      v4l2_ctrl_handler_init(&sensor->ctrls, 3);
++      v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++                        V4L2_CID_AUTOGAIN,
++                        0,  /* min */
++                        1,  /* max */
++                        1,  /* step */
++                        1); /* default */
++      v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++                        V4L2_CID_AUTO_WHITE_BALANCE,
++                        0,  /* min */
++                        1,  /* max */
++                        1,  /* step */
++                        1); /* default */
++      v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
++                             V4L2_CID_EXPOSURE_AUTO,
++                             V4L2_EXPOSURE_MANUAL,  /* max */
++                             0,                     /* skip_mask */
++                             V4L2_EXPOSURE_AUTO);   /* default */
++      ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++                               V4L2_CID_EXPOSURE,
++                               4,     /* min lines */
++                               65535, /* max lines (4+8+4 bits)*/
++                               1,     /* step */
++                               1000); /* default number of lines */
++      ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
++      ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++                               V4L2_CID_ANALOGUE_GAIN,
++                               16,   /* min, 16 = 1.0x */
++                               1023, /* max (10 bits) */
++                               1,    /* step */
++                               32);  /* default, 32 = 2.0x */
++      ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
++
++      if (sensor->ctrls.error) {
++              ret = sensor->ctrls.error;
++              dev_err(&client->dev, "%s control init failed (%d)\n",
++                      __func__, ret);
++              goto error;
++      }
++      sensor->sd.ctrl_handler = &sensor->ctrls;
++
+       /* Set the default mode before we init the subdev */
+       sensor->mode = OV5647_DEFAULT_MODE;
+@@ -828,6 +999,7 @@ static int ov5647_probe(struct i2c_clien
+ error:
+       media_entity_cleanup(&sd->entity);
+ mutex_remove:
++      v4l2_ctrl_handler_free(&sensor->ctrls);
+       mutex_destroy(&sensor->lock);
+       return ret;
+ }
+@@ -839,6 +1011,7 @@ static int ov5647_remove(struct i2c_clie
+       v4l2_async_unregister_subdev(&ov5647->sd);
+       media_entity_cleanup(&ov5647->sd.entity);
++      v4l2_ctrl_handler_free(&ov5647->ctrls);
+       v4l2_device_unregister_subdev(sd);
+       mutex_destroy(&ov5647->lock);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0470-media-ov5647-Add-extra-10-bit-sensor-modes.patch b/target/linux/bcm27xx/patches-5.4/950-0470-media-ov5647-Add-extra-10-bit-sensor-modes.patch
new file mode 100644 (file)
index 0000000..9e40b51
--- /dev/null
@@ -0,0 +1,549 @@
+From 28c0004a54ce9b2c5862b38408952583b07458f9 Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:28 +0000
+Subject: [PATCH] media: ov5647: Add extra 10-bit sensor modes.
+
+The 8-bit VGA mode remains, we add the following 10-bit modes:
+
+Mode 0: 2592x1944 full resolution.
+
+Mode 1: 1920x1080 full resolution, but centre-cropped.
+(This mode achieves 30fps, mode 0 does not.)
+
+Mode 2: 1296x972 full field-of-view 2x2 binned mode.
+
+Mode 3: VGA full field of view mode.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 463 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 452 insertions(+), 11 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -111,6 +111,7 @@ struct ov5647 {
+       struct gpio_desc                *pwdn;
+       unsigned int                    flags;
+       struct v4l2_ctrl_handler        ctrls;
++      bool                            write_mode_regs;
+ };
+ static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+@@ -130,7 +131,7 @@ static struct regval_list sensor_oe_enab
+       {0x3002, 0xe4},
+ };
+-static struct regval_list ov5647_640x480[] = {
++static struct regval_list ov5647_640x480_8bit[] = {
+       {0x0100, 0x00},
+       {0x0103, 0x01},
+       {0x3034, 0x08},
+@@ -220,9 +221,378 @@ static struct regval_list ov5647_640x480
+       {0x0100, 0x01},
+ };
++static struct regval_list ov5647_2592x1944_10bit[] = {
++      {0x0100, 0x00},
++      {0x0103, 0x01},
++      {0x3034, 0x1a},
++      {0x3035, 0x21},
++      {0x3036, 0x69},
++      {0x303c, 0x11},
++      {0x3106, 0xf5},
++      {0x3821, 0x06},
++      {0x3820, 0x00},
++      {0x3827, 0xec},
++      {0x370c, 0x03},
++      {0x3612, 0x5b},
++      {0x3618, 0x04},
++      {0x5000, 0x06},
++      {0x5002, 0x41},
++      {0x5003, 0x08},
++      {0x5a00, 0x08},
++      {0x3000, 0x00},
++      {0x3001, 0x00},
++      {0x3002, 0x00},
++      {0x3016, 0x08},
++      {0x3017, 0xe0},
++      {0x3018, 0x44},
++      {0x301c, 0xf8},
++      {0x301d, 0xf0},
++      {0x3a18, 0x00},
++      {0x3a19, 0xf8},
++      {0x3c01, 0x80},
++      {0x3b07, 0x0c},
++      {0x380c, 0x0b},
++      {0x380d, 0x1c},
++      {0x380e, 0x07},
++      {0x380f, 0xb0},
++      {0x3814, 0x11},
++      {0x3815, 0x11},
++      {0x3708, 0x64},
++      {0x3709, 0x12},
++      {0x3808, 0x0a},
++      {0x3809, 0x20},
++      {0x380a, 0x07},
++      {0x380b, 0x98},
++      {0x3800, 0x00},
++      {0x3801, 0x00},
++      {0x3802, 0x00},
++      {0x3803, 0x00},
++      {0x3804, 0x0a},
++      {0x3805, 0x3f},
++      {0x3806, 0x07},
++      {0x3807, 0xa3},
++      {0x3811, 0x10},
++      {0x3813, 0x06},
++      {0x3630, 0x2e},
++      {0x3632, 0xe2},
++      {0x3633, 0x23},
++      {0x3634, 0x44},
++      {0x3636, 0x06},
++      {0x3620, 0x64},
++      {0x3621, 0xe0},
++      {0x3600, 0x37},
++      {0x3704, 0xa0},
++      {0x3703, 0x5a},
++      {0x3715, 0x78},
++      {0x3717, 0x01},
++      {0x3731, 0x02},
++      {0x370b, 0x60},
++      {0x3705, 0x1a},
++      {0x3f05, 0x02},
++      {0x3f06, 0x10},
++      {0x3f01, 0x0a},
++      {0x3a08, 0x01},
++      {0x3a09, 0x28},
++      {0x3a0a, 0x00},
++      {0x3a0b, 0xf6},
++      {0x3a0d, 0x08},
++      {0x3a0e, 0x06},
++      {0x3a0f, 0x58},
++      {0x3a10, 0x50},
++      {0x3a1b, 0x58},
++      {0x3a1e, 0x50},
++      {0x3a11, 0x60},
++      {0x3a1f, 0x28},
++      {0x4001, 0x02},
++      {0x4004, 0x04},
++      {0x4000, 0x09},
++      {0x4837, 0x19},
++      {0x4800, 0x24},
++      {0x3503, 0x03},
++      {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_1080p30_10bit[] = {
++      {0x0100, 0x00},
++      {0x0103, 0x01},
++      {0x3034, 0x1a},
++      {0x3035, 0x21},
++      {0x3036, 0x62},
++      {0x303c, 0x11},
++      {0x3106, 0xf5},
++      {0x3821, 0x06},
++      {0x3820, 0x00},
++      {0x3827, 0xec},
++      {0x370c, 0x03},
++      {0x3612, 0x5b},
++      {0x3618, 0x04},
++      {0x5000, 0x06},
++      {0x5002, 0x41},
++      {0x5003, 0x08},
++      {0x5a00, 0x08},
++      {0x3000, 0x00},
++      {0x3001, 0x00},
++      {0x3002, 0x00},
++      {0x3016, 0x08},
++      {0x3017, 0xe0},
++      {0x3018, 0x44},
++      {0x301c, 0xf8},
++      {0x301d, 0xf0},
++      {0x3a18, 0x00},
++      {0x3a19, 0xf8},
++      {0x3c01, 0x80},
++      {0x3b07, 0x0c},
++      {0x380c, 0x09},
++      {0x380d, 0x70},
++      {0x380e, 0x04},
++      {0x380f, 0x50},
++      {0x3814, 0x11},
++      {0x3815, 0x11},
++      {0x3708, 0x64},
++      {0x3709, 0x12},
++      {0x3808, 0x07},
++      {0x3809, 0x80},
++      {0x380a, 0x04},
++      {0x380b, 0x38},
++      {0x3800, 0x01},
++      {0x3801, 0x5c},
++      {0x3802, 0x01},
++      {0x3803, 0xb2},
++      {0x3804, 0x08},
++      {0x3805, 0xe3},
++      {0x3806, 0x05},
++      {0x3807, 0xf1},
++      {0x3811, 0x04},
++      {0x3813, 0x02},
++      {0x3630, 0x2e},
++      {0x3632, 0xe2},
++      {0x3633, 0x23},
++      {0x3634, 0x44},
++      {0x3636, 0x06},
++      {0x3620, 0x64},
++      {0x3621, 0xe0},
++      {0x3600, 0x37},
++      {0x3704, 0xa0},
++      {0x3703, 0x5a},
++      {0x3715, 0x78},
++      {0x3717, 0x01},
++      {0x3731, 0x02},
++      {0x370b, 0x60},
++      {0x3705, 0x1a},
++      {0x3f05, 0x02},
++      {0x3f06, 0x10},
++      {0x3f01, 0x0a},
++      {0x3a08, 0x01},
++      {0x3a09, 0x4b},
++      {0x3a0a, 0x01},
++      {0x3a0b, 0x13},
++      {0x3a0d, 0x04},
++      {0x3a0e, 0x03},
++      {0x3a0f, 0x58},
++      {0x3a10, 0x50},
++      {0x3a1b, 0x58},
++      {0x3a1e, 0x50},
++      {0x3a11, 0x60},
++      {0x3a1f, 0x28},
++      {0x4001, 0x02},
++      {0x4004, 0x04},
++      {0x4000, 0x09},
++      {0x4837, 0x19},
++      {0x4800, 0x34},
++      {0x3503, 0x03},
++      {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_2x2binned_10bit[] = {
++      {0x0100, 0x00},
++      {0x0103, 0x01},
++      {0x3034, 0x1A},
++      {0x3035, 0x21},
++      {0x3036, 0x62},
++      {0x303C, 0x11},
++      {0x3106, 0xF5},
++      {0x3827, 0xEC},
++      {0x370C, 0x03},
++      {0x3612, 0x59},
++      {0x3618, 0x00},
++      {0x5000, 0x06},
++      {0x5002, 0x41},
++      {0x5003, 0x08},
++      {0x5A00, 0x08},
++      {0x3000, 0x00},
++      {0x3001, 0x00},
++      {0x3002, 0x00},
++      {0x3016, 0x08},
++      {0x3017, 0xE0},
++      {0x3018, 0x44},
++      {0x301C, 0xF8},
++      {0x301D, 0xF0},
++      {0x3A18, 0x00},
++      {0x3A19, 0xF8},
++      {0x3C01, 0x80},
++      {0x3B07, 0x0C},
++      {0x3800, 0x00},
++      {0x3801, 0x00},
++      {0x3802, 0x00},
++      {0x3803, 0x00},
++      {0x3804, 0x0A},
++      {0x3805, 0x3F},
++      {0x3806, 0x07},
++      {0x3807, 0xA3},
++      {0x3808, 0x05},
++      {0x3809, 0x10},
++      {0x380A, 0x03},
++      {0x380B, 0xCC},
++      {0x380C, 0x07},
++      {0x380D, 0x68},
++      {0x3811, 0x0c},
++      {0x3813, 0x06},
++      {0x3814, 0x31},
++      {0x3815, 0x31},
++      {0x3630, 0x2E},
++      {0x3632, 0xE2},
++      {0x3633, 0x23},
++      {0x3634, 0x44},
++      {0x3636, 0x06},
++      {0x3620, 0x64},
++      {0x3621, 0xE0},
++      {0x3600, 0x37},
++      {0x3704, 0xA0},
++      {0x3703, 0x5A},
++      {0x3715, 0x78},
++      {0x3717, 0x01},
++      {0x3731, 0x02},
++      {0x370B, 0x60},
++      {0x3705, 0x1A},
++      {0x3F05, 0x02},
++      {0x3F06, 0x10},
++      {0x3F01, 0x0A},
++      {0x3A08, 0x01},
++      {0x3A09, 0x28},
++      {0x3A0A, 0x00},
++      {0x3A0B, 0xF6},
++      {0x3A0D, 0x08},
++      {0x3A0E, 0x06},
++      {0x3A0F, 0x58},
++      {0x3A10, 0x50},
++      {0x3A1B, 0x58},
++      {0x3A1E, 0x50},
++      {0x3A11, 0x60},
++      {0x3A1F, 0x28},
++      {0x4001, 0x02},
++      {0x4004, 0x04},
++      {0x4000, 0x09},
++      {0x4837, 0x16},
++      {0x4800, 0x24},
++      {0x3503, 0x03},
++      {0x3820, 0x41},
++      {0x3821, 0x07},
++      {0x380E, 0x05},
++      {0x380F, 0x9B},
++      {0x350A, 0x00},
++      {0x350B, 0x10},
++      {0x3500, 0x00},
++      {0x3501, 0x1A},
++      {0x3502, 0xF0},
++      {0x3212, 0xA0},
++      {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_640x480_10bit[] = {
++      {0x0100, 0x00},
++      {0x0103, 0x01},
++      {0x3035, 0x11},
++      {0x3036, 0x46},
++      {0x303c, 0x11},
++      {0x3821, 0x07},
++      {0x3820, 0x41},
++      {0x370c, 0x03},
++      {0x3612, 0x59},
++      {0x3618, 0x00},
++      {0x5000, 0x06},
++      {0x5003, 0x08},
++      {0x5a00, 0x08},
++      {0x3000, 0xff},
++      {0x3001, 0xff},
++      {0x3002, 0xff},
++      {0x301d, 0xf0},
++      {0x3a18, 0x00},
++      {0x3a19, 0xf8},
++      {0x3c01, 0x80},
++      {0x3b07, 0x0c},
++      {0x380c, 0x07},
++      {0x380d, 0x3c},
++      {0x380e, 0x01},
++      {0x380f, 0xf8},
++      {0x3814, 0x35},
++      {0x3815, 0x35},
++      {0x3708, 0x64},
++      {0x3709, 0x52},
++      {0x3808, 0x02},
++      {0x3809, 0x80},
++      {0x380a, 0x01},
++      {0x380b, 0xe0},
++      {0x3800, 0x00},
++      {0x3801, 0x10},
++      {0x3802, 0x00},
++      {0x3803, 0x00},
++      {0x3804, 0x0a},
++      {0x3805, 0x2f},
++      {0x3806, 0x07},
++      {0x3807, 0x9f},
++      {0x3630, 0x2e},
++      {0x3632, 0xe2},
++      {0x3633, 0x23},
++      {0x3634, 0x44},
++      {0x3620, 0x64},
++      {0x3621, 0xe0},
++      {0x3600, 0x37},
++      {0x3704, 0xa0},
++      {0x3703, 0x5a},
++      {0x3715, 0x78},
++      {0x3717, 0x01},
++      {0x3731, 0x02},
++      {0x370b, 0x60},
++      {0x3705, 0x1a},
++      {0x3f05, 0x02},
++      {0x3f06, 0x10},
++      {0x3f01, 0x0a},
++      {0x3a08, 0x01},
++      {0x3a09, 0x2e},
++      {0x3a0a, 0x00},
++      {0x3a0b, 0xfb},
++      {0x3a0d, 0x02},
++      {0x3a0e, 0x01},
++      {0x3a0f, 0x58},
++      {0x3a10, 0x50},
++      {0x3a1b, 0x58},
++      {0x3a1e, 0x50},
++      {0x3a11, 0x60},
++      {0x3a1f, 0x28},
++      {0x4001, 0x02},
++      {0x4004, 0x02},
++      {0x4000, 0x09},
++      {0x3000, 0x00},
++      {0x3001, 0x00},
++      {0x3002, 0x00},
++      {0x3017, 0xe0},
++      {0x301c, 0xfc},
++      {0x3636, 0x06},
++      {0x3016, 0x08},
++      {0x3827, 0xec},
++      {0x3018, 0x44},
++      {0x3035, 0x21},
++      {0x3106, 0xf5},
++      {0x3034, 0x1a},
++      {0x301c, 0xf8},
++      {0x4800, 0x34},
++      {0x3503, 0x03},
++      {0x0100, 0x01},
++};
++
+ static struct ov5647_mode supported_modes_8bit[] = {
+       /*
+-       * Original 8-bit VGA mode
++       * MODE 0: Original 8-bit VGA mode.
+        * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image.
+        */
+       {
+@@ -233,14 +603,70 @@ static struct ov5647_mode supported_mode
+                       .width = 640,
+                       .height = 480
+               },
+-              ov5647_640x480,
+-              ARRAY_SIZE(ov5647_640x480)
++              ov5647_640x480_8bit,
++              ARRAY_SIZE(ov5647_640x480_8bit)
+       },
+-      /* more modes below here... */
+ };
+ static struct ov5647_mode supported_modes_10bit[] = {
+-      /* no 10-bit modes yet */
++      /*
++       * MODE 0: 2592x1944 full resolution full FOV 10-bit mode.
++       */
++      {
++              {
++                      .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++                      .colorspace = V4L2_COLORSPACE_SRGB,
++                      .field = V4L2_FIELD_NONE,
++                      .width = 2592,
++                      .height = 1944
++              },
++              ov5647_2592x1944_10bit,
++              ARRAY_SIZE(ov5647_2592x1944_10bit)
++      },
++      /*
++       * MODE 1: 1080p30 10-bit mode.
++       * Full resolution centre-cropped down to 1080p.
++       */
++      {
++              {
++                      .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++                      .colorspace = V4L2_COLORSPACE_SRGB,
++                      .field = V4L2_FIELD_NONE,
++                      .width = 1920,
++                      .height = 1080
++              },
++              ov5647_1080p30_10bit,
++              ARRAY_SIZE(ov5647_1080p30_10bit)
++      },
++      /*
++       * MODE 2: 2x2 binned full FOV 10-bit mode.
++       */
++      {
++              {
++                      .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++                      .colorspace = V4L2_COLORSPACE_SRGB,
++                      .field = V4L2_FIELD_NONE,
++                      .width = 1296,
++                      .height = 972
++              },
++              ov5647_2x2binned_10bit,
++              ARRAY_SIZE(ov5647_2x2binned_10bit)
++      },
++      /*
++       * MODE 3: 10-bit VGA full FOV mode 60fps.
++       * 2x2 binned and subsampled down to VGA.
++       */
++      {
++              {
++                      .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++                      .colorspace = V4L2_COLORSPACE_SRGB,
++                      .field = V4L2_FIELD_NONE,
++                      .width = 640,
++                      .height = 480
++              },
++              ov5647_640x480_10bit,
++              ARRAY_SIZE(ov5647_640x480_10bit)
++      },
+ };
+ /* Use original 8-bit VGA mode as default. */
+@@ -343,11 +769,14 @@ static int __sensor_init(struct v4l2_sub
+       if (ret < 0)
+               return ret;
+-      ret = ov5647_write_array(sd, state->mode->reg_list,
+-                               state->mode->num_regs);
+-      if (ret < 0) {
+-              dev_err(&client->dev, "write sensor default regs error\n");
+-              return ret;
++      if (state->write_mode_regs) {
++              ret = ov5647_write_array(sd, state->mode->reg_list,
++                                       state->mode->num_regs);
++              if (ret < 0) {
++                      dev_err(&client->dev, "write sensor default regs error\n");
++                      return ret;
++              }
++              state->write_mode_regs = false;
+       }
+       ret = ov5647_set_virtual_channel(sd, 0);
+@@ -475,6 +904,9 @@ static int ov5647_sensor_power(struct v4
+                               "Camera not available, check Power\n");
+                       goto out;
+               }
++
++              /* Write out the register set over I2C on stream-on. */
++              ov5647->write_mode_regs = true;
+       } else if (!on && ov5647->power_count == 1) {
+               dev_dbg(&client->dev, "OV5647 power off\n");
+@@ -650,6 +1082,12 @@ static int ov5647_set_fmt(struct v4l2_su
+               framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               *framefmt = format->format;
+       } else {
++              /*
++               * If we have changed modes, write the I2C register list on
++               * a stream_on().
++               */
++              if (state->mode != mode)
++                      state->write_mode_regs = true;
+               state->mode = mode;
+       }
+@@ -967,6 +1405,9 @@ static int ov5647_probe(struct i2c_clien
+       /* Set the default mode before we init the subdev */
+       sensor->mode = OV5647_DEFAULT_MODE;
++      /* Write out the register set over I2C on stream-on. */
++      sensor->write_mode_regs = true;
++
+       sd = &sensor->sd;
+       v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
+       sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0471-media-ov5647-change-defaults-to-better-match-raw-cam.patch b/target/linux/bcm27xx/patches-5.4/950-0471-media-ov5647-change-defaults-to-better-match-raw-cam.patch
new file mode 100644 (file)
index 0000000..58d23b7
--- /dev/null
@@ -0,0 +1,59 @@
+From 8bc19baeeca276374bed2d2ec95029d34fd93d7d Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:32 +0000
+Subject: [PATCH] media: ov5647: change defaults to better match raw
+ camera applications.
+
+Specifically:
+
+* AWB is now off by default.
+
+* AEC/AGC is also off by default.
+
+* The default mode is changed to the 10-bit 2x2 binned mode.
+
+AWB and AEC/AGC can be re-enabled using the usual V4L2 controls. The
+original 8-bit mode will be respected if an application requests the
+8-bit format.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -669,8 +669,8 @@ static struct ov5647_mode supported_mode
+       },
+ };
+-/* Use original 8-bit VGA mode as default. */
+-#define OV5647_DEFAULT_MODE (&supported_modes_8bit[0])
++/* Use 2x2 binned 10-bit mode as default. */
++#define OV5647_DEFAULT_MODE (&supported_modes_10bit[2])
+ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+ {
+@@ -1367,18 +1367,18 @@ static int ov5647_probe(struct i2c_clien
+                         0,  /* min */
+                         1,  /* max */
+                         1,  /* step */
+-                        1); /* default */
++                        0); /* default */
+       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+                         V4L2_CID_AUTO_WHITE_BALANCE,
+                         0,  /* min */
+                         1,  /* max */
+                         1,  /* step */
+-                        1); /* default */
++                        0); /* default */
+       v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
+                              V4L2_CID_EXPOSURE_AUTO,
+                              V4L2_EXPOSURE_MANUAL,  /* max */
+                              0,                     /* skip_mask */
+-                             V4L2_EXPOSURE_AUTO);   /* default */
++                             V4L2_EXPOSURE_MANUAL); /* default */
+       ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+                                V4L2_CID_EXPOSURE,
+                                4,     /* min lines */
diff --git a/target/linux/bcm27xx/patches-5.4/950-0472-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch b/target/linux/bcm27xx/patches-5.4/950-0472-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch
new file mode 100644 (file)
index 0000000..0b48018
--- /dev/null
@@ -0,0 +1,79 @@
+From c0b2ca6abdde60a111fd6d3257be78c7f44e16ff Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime@cerno.tech>
+Date: Thu, 26 Dec 2019 15:44:31 +0100
+Subject: [PATCH] drm/vc4: fkms: Change crtc_state structure name to
+ avoid conflict
+
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -260,7 +260,7 @@ static inline struct vc4_crtc *to_vc4_cr
+       return container_of(crtc, struct vc4_crtc, base);
+ }
+-struct vc4_crtc_state {
++struct fkms_crtc_state {
+       struct drm_crtc_state base;
+       struct {
+@@ -271,10 +271,10 @@ struct vc4_crtc_state {
+       } margins;
+ };
+-static inline struct vc4_crtc_state *
+-to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++static inline struct fkms_crtc_state *
++to_fkms_crtc_state(struct drm_crtc_state *crtc_state)
+ {
+-      return (struct vc4_crtc_state *)crtc_state;
++      return (struct fkms_crtc_state *)crtc_state;
+ }
+ struct vc4_fkms_encoder {
+@@ -410,7 +410,7 @@ static void vc4_fkms_crtc_get_margins(st
+                                     unsigned int *left, unsigned int *right,
+                                     unsigned int *top, unsigned int *bottom)
+ {
+-      struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++      struct fkms_crtc_state *vc4_state = to_fkms_crtc_state(state);
+       struct drm_connector_state *conn_state;
+       struct drm_connector *conn;
+       int i;
+@@ -423,7 +423,7 @@ static void vc4_fkms_crtc_get_margins(st
+       /* We have to interate over all new connector states because
+        * vc4_fkms_crtc_get_margins() might be called before
+        * vc4_fkms_crtc_atomic_check() which means margins info in
+-       * vc4_crtc_state might be outdated.
++       * fkms_crtc_state might be outdated.
+        */
+       for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+               if (conn_state->crtc != state->crtc)
+@@ -1068,7 +1068,7 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+                                struct drm_crtc_state *state)
+ {
+-      struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++      struct fkms_crtc_state *vc4_state = to_fkms_crtc_state(state);
+       struct drm_connector *conn;
+       struct drm_connector_state *conn_state;
+       int i;
+@@ -1178,13 +1178,13 @@ static int vc4_page_flip(struct drm_crtc
+ static struct drm_crtc_state *
+ vc4_crtc_duplicate_state(struct drm_crtc *crtc)
+ {
+-      struct vc4_crtc_state *vc4_state, *old_vc4_state;
++      struct fkms_crtc_state *vc4_state, *old_vc4_state;
+       vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+       if (!vc4_state)
+               return NULL;
+-      old_vc4_state = to_vc4_crtc_state(crtc->state);
++      old_vc4_state = to_fkms_crtc_state(crtc->state);
+       vc4_state->margins = old_vc4_state->margins;
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
diff --git a/target/linux/bcm27xx/patches-5.4/950-0473-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch b/target/linux/bcm27xx/patches-5.4/950-0473-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch
new file mode 100644 (file)
index 0000000..ac4fe16
--- /dev/null
@@ -0,0 +1,55 @@
+From 0d392a430d7dc84d8654972e9dbfa4d13009d3e8 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 24 Jan 2020 14:22:06 +0000
+Subject: [PATCH] drm/fourcc: Add packed 10bit YUV 4:2:0 format
+
+Adds a format that is 3 10bit YUV 4:2:0 samples packed into
+a 32bit work (with 2 spare bits).
+
+Supported on Broadcom BCM2711 chips.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/drm_fourcc.c  |  3 +++
+ include/uapi/drm/drm_fourcc.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/drm_fourcc.c
++++ b/drivers/gpu/drm/drm_fourcc.c
+@@ -274,6 +274,9 @@ const struct drm_format_info *__drm_form
+               { .format = DRM_FORMAT_YUV420_10BIT,    .depth = 0,
+                 .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
+                 .is_yuv = true },
++              { .format = DRM_FORMAT_P030,            .depth = 0,  .num_planes = 2,
++                .char_per_block = { 4, 4, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
++                .hsub = 2, .vsub = 2, .is_yuv = true},
+       };
+       unsigned int i;
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -266,6 +266,13 @@ extern "C" {
+ #define DRM_FORMAT_P016               fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */
+ /*
++ * 2 plane YCbCr MSB aligned, 3 pixels packed into 4 bytes.
++ * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian
++ * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian
++ */
++#define DRM_FORMAT_P030               fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */
++
++/*
+  * 3 plane YCbCr
+  * index 0: Y plane, [7:0] Y
+  * index 1: Cb plane, [7:0] Cb
+@@ -593,6 +600,10 @@ extern "C" {
+  * and UV.  Some SAND-using hardware stores UV in a separate tiled
+  * image from Y to reduce the column height, which is not supported
+  * with these modifiers.
++ *
++ * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also
++ * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes
++ * wide, but as this is a 10 bpp format that translates to 96 pixels.
+  */
+ #define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \
diff --git a/target/linux/bcm27xx/patches-5.4/950-0474-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0474-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch
new file mode 100644 (file)
index 0000000..f6264ff
--- /dev/null
@@ -0,0 +1,71 @@
+From 531d3d5c89825bade52f4257d264bbb06775a6fa Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 24 Jan 2020 14:24:33 +0000
+Subject: [PATCH] drm/vc4: Add DRM_FORMAT_P030 support to firmware-kms
+
+Adds support for this format which is 3 10bit samples packed into
+4 bytes, as used by the HEVC codec block.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 21 ++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc_image_types.h   |  4 ++++
+ 2 files changed, 24 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -216,6 +216,10 @@ static const struct vc_image_format {
+               .vc_image = VC_IMAGE_YUV420SP,
+               .is_vu = 1,
+       },
++      {
++              .drm = DRM_FORMAT_P030,
++              .vc_image = VC_IMAGE_YUV10COL,
++      },
+ };
+ static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
+@@ -622,7 +626,15 @@ static int vc4_plane_to_mb(struct drm_pl
+               }
+               break;
+       case DRM_FORMAT_MOD_BROADCOM_SAND128:
+-              mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++              switch (mb->plane.vc_image_type) {
++              case VC_IMAGE_YUV420SP:
++                      mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++                      break;
++              /* VC_IMAGE_YUV10COL could be included in here, but it is only
++               * valid as a SAND128 format, so the table at the top will have
++               * already set the correct format.
++               */
++              }
+               /* Note that the column pitch is passed across in lines, not
+                * bytes.
+                */
+@@ -707,6 +719,13 @@ static bool vc4_fkms_format_mod_supporte
+               case DRM_FORMAT_MOD_BROADCOM_SAND128:
+                       return true;
+               default:
++                      return false;
++              }
++      case DRM_FORMAT_P030:
++              switch (fourcc_mod_broadcom_mod(modifier)) {
++              case DRM_FORMAT_MOD_BROADCOM_SAND128:
++                      return true;
++              default:
+                       return false;
+               }
+       case DRM_FORMAT_NV21:
+--- a/drivers/gpu/drm/vc4/vc_image_types.h
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -139,6 +139,10 @@ enum {
+       VC_IMAGE_YUV_UV_16,
+       /* YUV4:2:0 with U,V in side-by-side format */
+       VC_IMAGE_YUV420_S,
++      /* 10-bit YUV 420 column image format */
++      VC_IMAGE_YUV10COL,
++      /* 32-bpp, 10-bit R/G/B, 2-bit Alpha */
++      VC_IMAGE_RGBA1010102,
+       VC_IMAGE_MAX,     /* bounds for error checking */
+       VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,